Merge pull request #10432 from alenkacz/patch-1

Print out some cli error message for getservices
diff --git a/BUILD b/BUILD
index 6c4d31d..1991c86 100644
--- a/BUILD
+++ b/BUILD
@@ -41,7 +41,7 @@
 
 core_version = "3.0.0-dev"
 
-version = "1.2.0"
+version = "1.3.0-dev"
 
 grpc_cc_library(
     name = "gpr",
@@ -67,6 +67,7 @@
         "grpc_lb_policy_pick_first",
         "grpc_lb_policy_round_robin",
         "grpc_load_reporting",
+        "grpc_max_age_filter",
         "grpc_resolver_dns_ares",
         "grpc_resolver_dns_native",
         "grpc_resolver_sockaddr",
@@ -108,6 +109,7 @@
         "grpc_lb_policy_pick_first",
         "grpc_lb_policy_round_robin",
         "grpc_load_reporting",
+        "grpc_max_age_filter",
         "grpc_resolver_dns_native",
         "grpc_resolver_sockaddr",
         "grpc_transport_chttp2_client_insecure",
@@ -186,11 +188,15 @@
         "src/compiler/objective_c_generator_helpers.h",
         "src/compiler/php_generator.h",
         "src/compiler/php_generator_helpers.h",
+        "src/compiler/protobuf_plugin.h",
         "src/compiler/python_generator.h",
+        "src/compiler/python_generator_helpers.h",
+        "src/compiler/python_private_generator.h",
         "src/compiler/ruby_generator.h",
         "src/compiler/ruby_generator_helpers-inl.h",
         "src/compiler/ruby_generator_map-inl.h",
         "src/compiler/ruby_generator_string-inl.h",
+        "src/compiler/schema_interface.h",
     ],
     external_deps = [
         "protobuf_clib",
@@ -436,7 +442,6 @@
         "src/core/lib/channel/handshaker_registry.c",
         "src/core/lib/channel/http_client_filter.c",
         "src/core/lib/channel/http_server_filter.c",
-        "src/core/lib/channel/max_age_filter.c",
         "src/core/lib/channel/message_size_filter.c",
         "src/core/lib/compression/compression.c",
         "src/core/lib/compression/message_compress.c",
@@ -564,7 +569,6 @@
         "src/core/lib/channel/handshaker_registry.h",
         "src/core/lib/channel/http_client_filter.h",
         "src/core/lib/channel/http_server_filter.h",
-        "src/core/lib/channel/max_age_filter.h",
         "src/core/lib/channel/message_size_filter.h",
         "src/core/lib/compression/algorithm_metadata.h",
         "src/core/lib/compression/message_compress.h",
@@ -689,46 +693,60 @@
 grpc_cc_library(
     name = "grpc_client_channel",
     srcs = [
-        "src/core/ext/client_channel/channel_connectivity.c",
-        "src/core/ext/client_channel/client_channel.c",
-        "src/core/ext/client_channel/client_channel_factory.c",
-        "src/core/ext/client_channel/client_channel_plugin.c",
-        "src/core/ext/client_channel/connector.c",
-        "src/core/ext/client_channel/http_connect_handshaker.c",
-        "src/core/ext/client_channel/http_proxy.c",
-        "src/core/ext/client_channel/lb_policy.c",
-        "src/core/ext/client_channel/lb_policy_factory.c",
-        "src/core/ext/client_channel/lb_policy_registry.c",
-        "src/core/ext/client_channel/parse_address.c",
-        "src/core/ext/client_channel/proxy_mapper.c",
-        "src/core/ext/client_channel/proxy_mapper_registry.c",
-        "src/core/ext/client_channel/resolver.c",
-        "src/core/ext/client_channel/resolver_factory.c",
-        "src/core/ext/client_channel/resolver_registry.c",
-        "src/core/ext/client_channel/retry_throttle.c",
-        "src/core/ext/client_channel/subchannel.c",
-        "src/core/ext/client_channel/subchannel_index.c",
-        "src/core/ext/client_channel/uri_parser.c",
+        "src/core/ext/filters/client_channel/channel_connectivity.c",
+        "src/core/ext/filters/client_channel/client_channel.c",
+        "src/core/ext/filters/client_channel/client_channel_factory.c",
+        "src/core/ext/filters/client_channel/client_channel_plugin.c",
+        "src/core/ext/filters/client_channel/connector.c",
+        "src/core/ext/filters/client_channel/http_connect_handshaker.c",
+        "src/core/ext/filters/client_channel/http_proxy.c",
+        "src/core/ext/filters/client_channel/lb_policy.c",
+        "src/core/ext/filters/client_channel/lb_policy_factory.c",
+        "src/core/ext/filters/client_channel/lb_policy_registry.c",
+        "src/core/ext/filters/client_channel/parse_address.c",
+        "src/core/ext/filters/client_channel/proxy_mapper.c",
+        "src/core/ext/filters/client_channel/proxy_mapper_registry.c",
+        "src/core/ext/filters/client_channel/resolver.c",
+        "src/core/ext/filters/client_channel/resolver_factory.c",
+        "src/core/ext/filters/client_channel/resolver_registry.c",
+        "src/core/ext/filters/client_channel/retry_throttle.c",
+        "src/core/ext/filters/client_channel/subchannel.c",
+        "src/core/ext/filters/client_channel/subchannel_index.c",
+        "src/core/ext/filters/client_channel/uri_parser.c",
     ],
     hdrs = [
-        "src/core/ext/client_channel/client_channel.h",
-        "src/core/ext/client_channel/client_channel_factory.h",
-        "src/core/ext/client_channel/connector.h",
-        "src/core/ext/client_channel/http_connect_handshaker.h",
-        "src/core/ext/client_channel/http_proxy.h",
-        "src/core/ext/client_channel/lb_policy.h",
-        "src/core/ext/client_channel/lb_policy_factory.h",
-        "src/core/ext/client_channel/lb_policy_registry.h",
-        "src/core/ext/client_channel/parse_address.h",
-        "src/core/ext/client_channel/proxy_mapper.h",
-        "src/core/ext/client_channel/proxy_mapper_registry.h",
-        "src/core/ext/client_channel/resolver.h",
-        "src/core/ext/client_channel/resolver_factory.h",
-        "src/core/ext/client_channel/resolver_registry.h",
-        "src/core/ext/client_channel/retry_throttle.h",
-        "src/core/ext/client_channel/subchannel.h",
-        "src/core/ext/client_channel/subchannel_index.h",
-        "src/core/ext/client_channel/uri_parser.h",
+        "src/core/ext/filters/client_channel/client_channel.h",
+        "src/core/ext/filters/client_channel/client_channel_factory.h",
+        "src/core/ext/filters/client_channel/connector.h",
+        "src/core/ext/filters/client_channel/http_connect_handshaker.h",
+        "src/core/ext/filters/client_channel/http_proxy.h",
+        "src/core/ext/filters/client_channel/lb_policy.h",
+        "src/core/ext/filters/client_channel/lb_policy_factory.h",
+        "src/core/ext/filters/client_channel/lb_policy_registry.h",
+        "src/core/ext/filters/client_channel/parse_address.h",
+        "src/core/ext/filters/client_channel/proxy_mapper.h",
+        "src/core/ext/filters/client_channel/proxy_mapper_registry.h",
+        "src/core/ext/filters/client_channel/resolver.h",
+        "src/core/ext/filters/client_channel/resolver_factory.h",
+        "src/core/ext/filters/client_channel/resolver_registry.h",
+        "src/core/ext/filters/client_channel/retry_throttle.h",
+        "src/core/ext/filters/client_channel/subchannel.h",
+        "src/core/ext/filters/client_channel/subchannel_index.h",
+        "src/core/ext/filters/client_channel/uri_parser.h",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_max_age_filter",
+    srcs = [
+        "src/core/ext/filters/max_age/max_age_filter.c",
+    ],
+    hdrs = [
+        "src/core/ext/filters/max_age/max_age_filter.h",
     ],
     language = "c",
     deps = [
@@ -757,16 +775,16 @@
 grpc_cc_library(
     name = "grpc_lb_policy_grpclb",
     srcs = [
-        "src/core/ext/lb_policy/grpclb/grpclb.c",
-        "src/core/ext/lb_policy/grpclb/grpclb_channel.c",
-        "src/core/ext/lb_policy/grpclb/load_balancer_api.c",
-        "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.c",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
     ],
     hdrs = [
-        "src/core/ext/lb_policy/grpclb/grpclb.h",
-        "src/core/ext/lb_policy/grpclb/grpclb_channel.h",
-        "src/core/ext/lb_policy/grpclb/load_balancer_api.h",
-        "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
     ],
     external_deps = [
         "nanopb",
@@ -781,16 +799,16 @@
 grpc_cc_library(
     name = "grpc_lb_policy_grpclb_secure",
     srcs = [
-        "src/core/ext/lb_policy/grpclb/grpclb.c",
-        "src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c",
-        "src/core/ext/lb_policy/grpclb/load_balancer_api.c",
-        "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
     ],
     hdrs = [
-        "src/core/ext/lb_policy/grpclb/grpclb.h",
-        "src/core/ext/lb_policy/grpclb/grpclb_channel.h",
-        "src/core/ext/lb_policy/grpclb/load_balancer_api.h",
-        "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
+        "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
     ],
     external_deps = [
         "nanopb",
@@ -806,7 +824,7 @@
 grpc_cc_library(
     name = "grpc_lb_policy_pick_first",
     srcs = [
-        "src/core/ext/lb_policy/pick_first/pick_first.c",
+        "src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c",
     ],
     language = "c",
     deps = [
@@ -818,7 +836,7 @@
 grpc_cc_library(
     name = "grpc_lb_policy_round_robin",
     srcs = [
-        "src/core/ext/lb_policy/round_robin/round_robin.c",
+        "src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c",
     ],
     language = "c",
     deps = [
@@ -830,12 +848,12 @@
 grpc_cc_library(
     name = "grpc_load_reporting",
     srcs = [
-        "src/core/ext/load_reporting/load_reporting.c",
-        "src/core/ext/load_reporting/load_reporting_filter.c",
+        "src/core/ext/filters/load_reporting/load_reporting.c",
+        "src/core/ext/filters/load_reporting/load_reporting_filter.c",
     ],
     hdrs = [
-        "src/core/ext/load_reporting/load_reporting.h",
-        "src/core/ext/load_reporting/load_reporting_filter.h",
+        "src/core/ext/filters/load_reporting/load_reporting.h",
+        "src/core/ext/filters/load_reporting/load_reporting_filter.h",
     ],
     language = "c",
     deps = [
@@ -846,7 +864,7 @@
 grpc_cc_library(
     name = "grpc_resolver_dns_native",
     srcs = [
-        "src/core/ext/resolver/dns/native/dns_resolver.c",
+        "src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c",
     ],
     language = "c",
     deps = [
@@ -858,28 +876,28 @@
 grpc_cc_library(
     name = "grpc_resolver_dns_ares",
     srcs = [
-        "src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c",
-        "src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c",
-        "src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c",
+        "src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c",
+        "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c",
+        "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c",
     ],
     hdrs = [
-        "src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h",
-        "src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h",
+        "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h",
+        "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h",
+    ],
+    external_deps = [
+        "cares",
     ],
     language = "c",
     deps = [
         "grpc_base",
         "grpc_client_channel",
     ],
-    external_deps = [
-        "cares",
-    ],
 )
 
 grpc_cc_library(
     name = "grpc_resolver_sockaddr",
     srcs = [
-        "src/core/ext/resolver/sockaddr/sockaddr_resolver.c",
+        "src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c",
     ],
     language = "c",
     deps = [
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e3b2558..96ece1f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -626,6 +626,9 @@
 add_dependencies(buildtests_cxx bm_cq)
 endif()
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+add_dependencies(buildtests_cxx bm_cq_multiple_threads)
+endif()
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx bm_error)
 endif()
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -918,7 +921,6 @@
   src/core/lib/channel/handshaker_registry.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/max_age_filter.c
   src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
@@ -1083,47 +1085,47 @@
   src/core/tsi/transport_security.c
   src/core/ext/transport/chttp2/server/chttp2_server.c
   src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
-  src/core/ext/client_channel/channel_connectivity.c
-  src/core/ext/client_channel/client_channel.c
-  src/core/ext/client_channel/client_channel_factory.c
-  src/core/ext/client_channel/client_channel_plugin.c
-  src/core/ext/client_channel/connector.c
-  src/core/ext/client_channel/http_connect_handshaker.c
-  src/core/ext/client_channel/http_proxy.c
-  src/core/ext/client_channel/lb_policy.c
-  src/core/ext/client_channel/lb_policy_factory.c
-  src/core/ext/client_channel/lb_policy_registry.c
-  src/core/ext/client_channel/parse_address.c
-  src/core/ext/client_channel/proxy_mapper.c
-  src/core/ext/client_channel/proxy_mapper_registry.c
-  src/core/ext/client_channel/resolver.c
-  src/core/ext/client_channel/resolver_factory.c
-  src/core/ext/client_channel/resolver_registry.c
-  src/core/ext/client_channel/retry_throttle.c
-  src/core/ext/client_channel/subchannel.c
-  src/core/ext/client_channel/subchannel_index.c
-  src/core/ext/client_channel/uri_parser.c
+  src/core/ext/filters/client_channel/channel_connectivity.c
+  src/core/ext/filters/client_channel/client_channel.c
+  src/core/ext/filters/client_channel/client_channel_factory.c
+  src/core/ext/filters/client_channel/client_channel_plugin.c
+  src/core/ext/filters/client_channel/connector.c
+  src/core/ext/filters/client_channel/http_connect_handshaker.c
+  src/core/ext/filters/client_channel/http_proxy.c
+  src/core/ext/filters/client_channel/lb_policy.c
+  src/core/ext/filters/client_channel/lb_policy_factory.c
+  src/core/ext/filters/client_channel/lb_policy_registry.c
+  src/core/ext/filters/client_channel/parse_address.c
+  src/core/ext/filters/client_channel/proxy_mapper.c
+  src/core/ext/filters/client_channel/proxy_mapper_registry.c
+  src/core/ext/filters/client_channel/resolver.c
+  src/core/ext/filters/client_channel/resolver_factory.c
+  src/core/ext/filters/client_channel/resolver_registry.c
+  src/core/ext/filters/client_channel/retry_throttle.c
+  src/core/ext/filters/client_channel/subchannel.c
+  src/core/ext/filters/client_channel/subchannel_index.c
+  src/core/ext/filters/client_channel/uri_parser.c
   src/core/ext/transport/chttp2/client/chttp2_connector.c
   src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
   src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
   src/core/ext/transport/chttp2/client/insecure/channel_create.c
   src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
-  src/core/ext/lb_policy/grpclb/grpclb.c
-  src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c
-  src/core/ext/lb_policy/grpclb/load_balancer_api.c
-  src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+  src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
+  src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c
+  src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c
+  src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
   third_party/nanopb/pb_common.c
   third_party/nanopb/pb_decode.c
   third_party/nanopb/pb_encode.c
-  src/core/ext/lb_policy/pick_first/pick_first.c
-  src/core/ext/lb_policy/round_robin/round_robin.c
-  src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c
-  src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
-  src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c
-  src/core/ext/resolver/dns/native/dns_resolver.c
-  src/core/ext/resolver/sockaddr/sockaddr_resolver.c
-  src/core/ext/load_reporting/load_reporting.c
-  src/core/ext/load_reporting/load_reporting_filter.c
+  src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c
+  src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c
+  src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
+  src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
+  src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
+  src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c
+  src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c
+  src/core/ext/filters/load_reporting/load_reporting.c
+  src/core/ext/filters/load_reporting/load_reporting_filter.c
   src/core/ext/census/base_resources.c
   src/core/ext/census/context.c
   src/core/ext/census/gen/census.pb.c
@@ -1138,6 +1140,7 @@
   src/core/ext/census/resource.c
   src/core/ext/census/trace_context.c
   src/core/ext/census/tracing.c
+  src/core/ext/filters/max_age/max_age_filter.c
   src/core/plugin_registry/grpc_plugin_registry.c
 )
 
@@ -1240,7 +1243,6 @@
   src/core/lib/channel/handshaker_registry.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/max_age_filter.c
   src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
@@ -1379,26 +1381,26 @@
   src/core/ext/transport/chttp2/transport/varint.c
   src/core/ext/transport/chttp2/transport/writing.c
   src/core/ext/transport/chttp2/alpn/alpn.c
-  src/core/ext/client_channel/channel_connectivity.c
-  src/core/ext/client_channel/client_channel.c
-  src/core/ext/client_channel/client_channel_factory.c
-  src/core/ext/client_channel/client_channel_plugin.c
-  src/core/ext/client_channel/connector.c
-  src/core/ext/client_channel/http_connect_handshaker.c
-  src/core/ext/client_channel/http_proxy.c
-  src/core/ext/client_channel/lb_policy.c
-  src/core/ext/client_channel/lb_policy_factory.c
-  src/core/ext/client_channel/lb_policy_registry.c
-  src/core/ext/client_channel/parse_address.c
-  src/core/ext/client_channel/proxy_mapper.c
-  src/core/ext/client_channel/proxy_mapper_registry.c
-  src/core/ext/client_channel/resolver.c
-  src/core/ext/client_channel/resolver_factory.c
-  src/core/ext/client_channel/resolver_registry.c
-  src/core/ext/client_channel/retry_throttle.c
-  src/core/ext/client_channel/subchannel.c
-  src/core/ext/client_channel/subchannel_index.c
-  src/core/ext/client_channel/uri_parser.c
+  src/core/ext/filters/client_channel/channel_connectivity.c
+  src/core/ext/filters/client_channel/client_channel.c
+  src/core/ext/filters/client_channel/client_channel_factory.c
+  src/core/ext/filters/client_channel/client_channel_plugin.c
+  src/core/ext/filters/client_channel/connector.c
+  src/core/ext/filters/client_channel/http_connect_handshaker.c
+  src/core/ext/filters/client_channel/http_proxy.c
+  src/core/ext/filters/client_channel/lb_policy.c
+  src/core/ext/filters/client_channel/lb_policy_factory.c
+  src/core/ext/filters/client_channel/lb_policy_registry.c
+  src/core/ext/filters/client_channel/parse_address.c
+  src/core/ext/filters/client_channel/proxy_mapper.c
+  src/core/ext/filters/client_channel/proxy_mapper_registry.c
+  src/core/ext/filters/client_channel/resolver.c
+  src/core/ext/filters/client_channel/resolver_factory.c
+  src/core/ext/filters/client_channel/resolver_registry.c
+  src/core/ext/filters/client_channel/retry_throttle.c
+  src/core/ext/filters/client_channel/subchannel.c
+  src/core/ext/filters/client_channel/subchannel_index.c
+  src/core/ext/filters/client_channel/uri_parser.c
   src/core/lib/http/httpcli_security_connector.c
   src/core/lib/security/context/security_context.c
   src/core/lib/security/credentials/composite/composite_credentials.c
@@ -1427,8 +1429,8 @@
   src/core/tsi/ssl_transport_security.c
   src/core/tsi/transport_security.c
   src/core/ext/transport/chttp2/client/chttp2_connector.c
-  src/core/ext/load_reporting/load_reporting.c
-  src/core/ext/load_reporting/load_reporting_filter.c
+  src/core/ext/filters/load_reporting/load_reporting.c
+  src/core/ext/filters/load_reporting/load_reporting_filter.c
   src/core/plugin_registry/grpc_cronet_plugin_registry.c
 )
 
@@ -1549,7 +1551,6 @@
   src/core/lib/channel/handshaker_registry.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/max_age_filter.c
   src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
@@ -1810,7 +1811,6 @@
   src/core/lib/channel/handshaker_registry.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/max_age_filter.c
   src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
@@ -1951,42 +1951,42 @@
   src/core/ext/transport/chttp2/client/insecure/channel_create.c
   src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
   src/core/ext/transport/chttp2/client/chttp2_connector.c
-  src/core/ext/client_channel/channel_connectivity.c
-  src/core/ext/client_channel/client_channel.c
-  src/core/ext/client_channel/client_channel_factory.c
-  src/core/ext/client_channel/client_channel_plugin.c
-  src/core/ext/client_channel/connector.c
-  src/core/ext/client_channel/http_connect_handshaker.c
-  src/core/ext/client_channel/http_proxy.c
-  src/core/ext/client_channel/lb_policy.c
-  src/core/ext/client_channel/lb_policy_factory.c
-  src/core/ext/client_channel/lb_policy_registry.c
-  src/core/ext/client_channel/parse_address.c
-  src/core/ext/client_channel/proxy_mapper.c
-  src/core/ext/client_channel/proxy_mapper_registry.c
-  src/core/ext/client_channel/resolver.c
-  src/core/ext/client_channel/resolver_factory.c
-  src/core/ext/client_channel/resolver_registry.c
-  src/core/ext/client_channel/retry_throttle.c
-  src/core/ext/client_channel/subchannel.c
-  src/core/ext/client_channel/subchannel_index.c
-  src/core/ext/client_channel/uri_parser.c
-  src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c
-  src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
-  src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c
-  src/core/ext/resolver/dns/native/dns_resolver.c
-  src/core/ext/resolver/sockaddr/sockaddr_resolver.c
-  src/core/ext/load_reporting/load_reporting.c
-  src/core/ext/load_reporting/load_reporting_filter.c
-  src/core/ext/lb_policy/grpclb/grpclb.c
-  src/core/ext/lb_policy/grpclb/grpclb_channel.c
-  src/core/ext/lb_policy/grpclb/load_balancer_api.c
-  src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+  src/core/ext/filters/client_channel/channel_connectivity.c
+  src/core/ext/filters/client_channel/client_channel.c
+  src/core/ext/filters/client_channel/client_channel_factory.c
+  src/core/ext/filters/client_channel/client_channel_plugin.c
+  src/core/ext/filters/client_channel/connector.c
+  src/core/ext/filters/client_channel/http_connect_handshaker.c
+  src/core/ext/filters/client_channel/http_proxy.c
+  src/core/ext/filters/client_channel/lb_policy.c
+  src/core/ext/filters/client_channel/lb_policy_factory.c
+  src/core/ext/filters/client_channel/lb_policy_registry.c
+  src/core/ext/filters/client_channel/parse_address.c
+  src/core/ext/filters/client_channel/proxy_mapper.c
+  src/core/ext/filters/client_channel/proxy_mapper_registry.c
+  src/core/ext/filters/client_channel/resolver.c
+  src/core/ext/filters/client_channel/resolver_factory.c
+  src/core/ext/filters/client_channel/resolver_registry.c
+  src/core/ext/filters/client_channel/retry_throttle.c
+  src/core/ext/filters/client_channel/subchannel.c
+  src/core/ext/filters/client_channel/subchannel_index.c
+  src/core/ext/filters/client_channel/uri_parser.c
+  src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
+  src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
+  src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
+  src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c
+  src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c
+  src/core/ext/filters/load_reporting/load_reporting.c
+  src/core/ext/filters/load_reporting/load_reporting_filter.c
+  src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
+  src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.c
+  src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c
+  src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
   third_party/nanopb/pb_common.c
   third_party/nanopb/pb_decode.c
   third_party/nanopb/pb_encode.c
-  src/core/ext/lb_policy/pick_first/pick_first.c
-  src/core/ext/lb_policy/round_robin/round_robin.c
+  src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c
+  src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c
   src/core/ext/census/base_resources.c
   src/core/ext/census/context.c
   src/core/ext/census/gen/census.pb.c
@@ -2001,6 +2001,7 @@
   src/core/ext/census/resource.c
   src/core/ext/census/trace_context.c
   src/core/ext/census/tracing.c
+  src/core/ext/filters/max_age/max_age_filter.c
   src/core/plugin_registry/grpc_unsecure_plugin_registry.c
 )
 
@@ -2226,7 +2227,6 @@
   src/core/lib/channel/handshaker_registry.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/max_age_filter.c
   src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
@@ -2557,7 +2557,6 @@
   src/core/lib/channel/handshaker_registry.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/max_age_filter.c
   src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
@@ -2699,26 +2698,26 @@
   src/core/ext/transport/chttp2/transport/varint.c
   src/core/ext/transport/chttp2/transport/writing.c
   src/core/ext/transport/chttp2/alpn/alpn.c
-  src/core/ext/client_channel/channel_connectivity.c
-  src/core/ext/client_channel/client_channel.c
-  src/core/ext/client_channel/client_channel_factory.c
-  src/core/ext/client_channel/client_channel_plugin.c
-  src/core/ext/client_channel/connector.c
-  src/core/ext/client_channel/http_connect_handshaker.c
-  src/core/ext/client_channel/http_proxy.c
-  src/core/ext/client_channel/lb_policy.c
-  src/core/ext/client_channel/lb_policy_factory.c
-  src/core/ext/client_channel/lb_policy_registry.c
-  src/core/ext/client_channel/parse_address.c
-  src/core/ext/client_channel/proxy_mapper.c
-  src/core/ext/client_channel/proxy_mapper_registry.c
-  src/core/ext/client_channel/resolver.c
-  src/core/ext/client_channel/resolver_factory.c
-  src/core/ext/client_channel/resolver_registry.c
-  src/core/ext/client_channel/retry_throttle.c
-  src/core/ext/client_channel/subchannel.c
-  src/core/ext/client_channel/subchannel_index.c
-  src/core/ext/client_channel/uri_parser.c
+  src/core/ext/filters/client_channel/channel_connectivity.c
+  src/core/ext/filters/client_channel/client_channel.c
+  src/core/ext/filters/client_channel/client_channel_factory.c
+  src/core/ext/filters/client_channel/client_channel_plugin.c
+  src/core/ext/filters/client_channel/connector.c
+  src/core/ext/filters/client_channel/http_connect_handshaker.c
+  src/core/ext/filters/client_channel/http_proxy.c
+  src/core/ext/filters/client_channel/lb_policy.c
+  src/core/ext/filters/client_channel/lb_policy_factory.c
+  src/core/ext/filters/client_channel/lb_policy_registry.c
+  src/core/ext/filters/client_channel/parse_address.c
+  src/core/ext/filters/client_channel/proxy_mapper.c
+  src/core/ext/filters/client_channel/proxy_mapper_registry.c
+  src/core/ext/filters/client_channel/resolver.c
+  src/core/ext/filters/client_channel/resolver_factory.c
+  src/core/ext/filters/client_channel/resolver_registry.c
+  src/core/ext/filters/client_channel/retry_throttle.c
+  src/core/ext/filters/client_channel/subchannel.c
+  src/core/ext/filters/client_channel/subchannel_index.c
+  src/core/ext/filters/client_channel/uri_parser.c
   src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
   src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
   src/core/ext/transport/chttp2/server/chttp2_server.c
@@ -3256,7 +3255,6 @@
   src/core/lib/channel/handshaker_registry.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
-  src/core/lib/channel/max_age_filter.c
   src/core/lib/channel/message_size_filter.c
   src/core/lib/compression/compression.c
   src/core/lib/compression/message_compress.c
@@ -4391,6 +4389,7 @@
   test/core/end2end/end2end_test_utils.c
   test/core/end2end/tests/authority_not_supported.c
   test/core/end2end/tests/bad_hostname.c
+  test/core/end2end/tests/bad_ping.c
   test/core/end2end/tests/binary_metadata.c
   test/core/end2end/tests/call_creds.c
   test/core/end2end/tests/cancel_after_accept.c
@@ -4488,6 +4487,7 @@
   test/core/end2end/end2end_test_utils.c
   test/core/end2end/tests/authority_not_supported.c
   test/core/end2end/tests/bad_hostname.c
+  test/core/end2end/tests/bad_ping.c
   test/core/end2end/tests/binary_metadata.c
   test/core/end2end/tests/cancel_after_accept.c
   test/core/end2end/tests/cancel_after_client_done.c
@@ -8982,6 +8982,49 @@
 if (gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
+add_executable(bm_cq_multiple_threads
+  test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
+  third_party/googletest/src/gtest-all.cc
+)
+
+
+target_include_directories(bm_cq_multiple_threads
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_BUILD_INCLUDE_DIR}
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+  PRIVATE third_party/googletest/include
+  PRIVATE third_party/googletest
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(bm_cq_multiple_threads
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_benchmark
+  benchmark
+  grpc++_test_util
+  grpc_test_util
+  grpc++
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif()
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+
 add_executable(bm_error
   test/cpp/microbenchmarks/bm_error.cc
   third_party/googletest/src/gtest-all.cc
diff --git a/Makefile b/Makefile
index 7499dbb..91a74f3 100644
--- a/Makefile
+++ b/Makefile
@@ -1105,6 +1105,7 @@
 bm_chttp2_transport: $(BINDIR)/$(CONFIG)/bm_chttp2_transport
 bm_closure: $(BINDIR)/$(CONFIG)/bm_closure
 bm_cq: $(BINDIR)/$(CONFIG)/bm_cq
+bm_cq_multiple_threads: $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads
 bm_error: $(BINDIR)/$(CONFIG)/bm_error
 bm_fullstack_streaming_ping_pong: $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_ping_pong
 bm_fullstack_streaming_pump: $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_pump
@@ -1530,6 +1531,7 @@
   $(BINDIR)/$(CONFIG)/bm_chttp2_transport \
   $(BINDIR)/$(CONFIG)/bm_closure \
   $(BINDIR)/$(CONFIG)/bm_cq \
+  $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads \
   $(BINDIR)/$(CONFIG)/bm_error \
   $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_ping_pong \
   $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_pump \
@@ -1648,6 +1650,7 @@
   $(BINDIR)/$(CONFIG)/bm_chttp2_transport \
   $(BINDIR)/$(CONFIG)/bm_closure \
   $(BINDIR)/$(CONFIG)/bm_cq \
+  $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads \
   $(BINDIR)/$(CONFIG)/bm_error \
   $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_ping_pong \
   $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_pump \
@@ -1997,6 +2000,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/bm_closure || ( echo test bm_closure failed ; exit 1 )
 	$(E) "[RUN]     Testing bm_cq"
 	$(Q) $(BINDIR)/$(CONFIG)/bm_cq || ( echo test bm_cq failed ; exit 1 )
+	$(E) "[RUN]     Testing bm_cq_multiple_threads"
+	$(Q) $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads || ( echo test bm_cq_multiple_threads failed ; exit 1 )
 	$(E) "[RUN]     Testing bm_error"
 	$(Q) $(BINDIR)/$(CONFIG)/bm_error || ( echo test bm_error failed ; exit 1 )
 	$(E) "[RUN]     Testing bm_fullstack_streaming_ping_pong"
@@ -2820,7 +2825,6 @@
     src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/max_age_filter.c \
     src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
@@ -2985,47 +2989,47 @@
     src/core/tsi/transport_security.c \
     src/core/ext/transport/chttp2/server/chttp2_server.c \
     src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
-    src/core/ext/client_channel/channel_connectivity.c \
-    src/core/ext/client_channel/client_channel.c \
-    src/core/ext/client_channel/client_channel_factory.c \
-    src/core/ext/client_channel/client_channel_plugin.c \
-    src/core/ext/client_channel/connector.c \
-    src/core/ext/client_channel/http_connect_handshaker.c \
-    src/core/ext/client_channel/http_proxy.c \
-    src/core/ext/client_channel/lb_policy.c \
-    src/core/ext/client_channel/lb_policy_factory.c \
-    src/core/ext/client_channel/lb_policy_registry.c \
-    src/core/ext/client_channel/parse_address.c \
-    src/core/ext/client_channel/proxy_mapper.c \
-    src/core/ext/client_channel/proxy_mapper_registry.c \
-    src/core/ext/client_channel/resolver.c \
-    src/core/ext/client_channel/resolver_factory.c \
-    src/core/ext/client_channel/resolver_registry.c \
-    src/core/ext/client_channel/retry_throttle.c \
-    src/core/ext/client_channel/subchannel.c \
-    src/core/ext/client_channel/subchannel_index.c \
-    src/core/ext/client_channel/uri_parser.c \
+    src/core/ext/filters/client_channel/channel_connectivity.c \
+    src/core/ext/filters/client_channel/client_channel.c \
+    src/core/ext/filters/client_channel/client_channel_factory.c \
+    src/core/ext/filters/client_channel/client_channel_plugin.c \
+    src/core/ext/filters/client_channel/connector.c \
+    src/core/ext/filters/client_channel/http_connect_handshaker.c \
+    src/core/ext/filters/client_channel/http_proxy.c \
+    src/core/ext/filters/client_channel/lb_policy.c \
+    src/core/ext/filters/client_channel/lb_policy_factory.c \
+    src/core/ext/filters/client_channel/lb_policy_registry.c \
+    src/core/ext/filters/client_channel/parse_address.c \
+    src/core/ext/filters/client_channel/proxy_mapper.c \
+    src/core/ext/filters/client_channel/proxy_mapper_registry.c \
+    src/core/ext/filters/client_channel/resolver.c \
+    src/core/ext/filters/client_channel/resolver_factory.c \
+    src/core/ext/filters/client_channel/resolver_registry.c \
+    src/core/ext/filters/client_channel/retry_throttle.c \
+    src/core/ext/filters/client_channel/subchannel.c \
+    src/core/ext/filters/client_channel/subchannel_index.c \
+    src/core/ext/filters/client_channel/uri_parser.c \
     src/core/ext/transport/chttp2/client/chttp2_connector.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
-    src/core/ext/lb_policy/grpclb/grpclb.c \
-    src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c \
-    src/core/ext/lb_policy/grpclb/load_balancer_api.c \
-    src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
     third_party/nanopb/pb_common.c \
     third_party/nanopb/pb_decode.c \
     third_party/nanopb/pb_encode.c \
-    src/core/ext/lb_policy/pick_first/pick_first.c \
-    src/core/ext/lb_policy/round_robin/round_robin.c \
-    src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c \
-    src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
-    src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c \
-    src/core/ext/resolver/dns/native/dns_resolver.c \
-    src/core/ext/resolver/sockaddr/sockaddr_resolver.c \
-    src/core/ext/load_reporting/load_reporting.c \
-    src/core/ext/load_reporting/load_reporting_filter.c \
+    src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c \
+    src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c \
+    src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c \
+    src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c \
+    src/core/ext/filters/load_reporting/load_reporting.c \
+    src/core/ext/filters/load_reporting/load_reporting_filter.c \
     src/core/ext/census/base_resources.c \
     src/core/ext/census/context.c \
     src/core/ext/census/gen/census.pb.c \
@@ -3040,6 +3044,7 @@
     src/core/ext/census/resource.c \
     src/core/ext/census/trace_context.c \
     src/core/ext/census/tracing.c \
+    src/core/ext/filters/max_age/max_age_filter.c \
     src/core/plugin_registry/grpc_plugin_registry.c \
 
 PUBLIC_HEADERS_C += \
@@ -3140,7 +3145,6 @@
     src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/max_age_filter.c \
     src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
@@ -3279,26 +3283,26 @@
     src/core/ext/transport/chttp2/transport/varint.c \
     src/core/ext/transport/chttp2/transport/writing.c \
     src/core/ext/transport/chttp2/alpn/alpn.c \
-    src/core/ext/client_channel/channel_connectivity.c \
-    src/core/ext/client_channel/client_channel.c \
-    src/core/ext/client_channel/client_channel_factory.c \
-    src/core/ext/client_channel/client_channel_plugin.c \
-    src/core/ext/client_channel/connector.c \
-    src/core/ext/client_channel/http_connect_handshaker.c \
-    src/core/ext/client_channel/http_proxy.c \
-    src/core/ext/client_channel/lb_policy.c \
-    src/core/ext/client_channel/lb_policy_factory.c \
-    src/core/ext/client_channel/lb_policy_registry.c \
-    src/core/ext/client_channel/parse_address.c \
-    src/core/ext/client_channel/proxy_mapper.c \
-    src/core/ext/client_channel/proxy_mapper_registry.c \
-    src/core/ext/client_channel/resolver.c \
-    src/core/ext/client_channel/resolver_factory.c \
-    src/core/ext/client_channel/resolver_registry.c \
-    src/core/ext/client_channel/retry_throttle.c \
-    src/core/ext/client_channel/subchannel.c \
-    src/core/ext/client_channel/subchannel_index.c \
-    src/core/ext/client_channel/uri_parser.c \
+    src/core/ext/filters/client_channel/channel_connectivity.c \
+    src/core/ext/filters/client_channel/client_channel.c \
+    src/core/ext/filters/client_channel/client_channel_factory.c \
+    src/core/ext/filters/client_channel/client_channel_plugin.c \
+    src/core/ext/filters/client_channel/connector.c \
+    src/core/ext/filters/client_channel/http_connect_handshaker.c \
+    src/core/ext/filters/client_channel/http_proxy.c \
+    src/core/ext/filters/client_channel/lb_policy.c \
+    src/core/ext/filters/client_channel/lb_policy_factory.c \
+    src/core/ext/filters/client_channel/lb_policy_registry.c \
+    src/core/ext/filters/client_channel/parse_address.c \
+    src/core/ext/filters/client_channel/proxy_mapper.c \
+    src/core/ext/filters/client_channel/proxy_mapper_registry.c \
+    src/core/ext/filters/client_channel/resolver.c \
+    src/core/ext/filters/client_channel/resolver_factory.c \
+    src/core/ext/filters/client_channel/resolver_registry.c \
+    src/core/ext/filters/client_channel/retry_throttle.c \
+    src/core/ext/filters/client_channel/subchannel.c \
+    src/core/ext/filters/client_channel/subchannel_index.c \
+    src/core/ext/filters/client_channel/uri_parser.c \
     src/core/lib/http/httpcli_security_connector.c \
     src/core/lib/security/context/security_context.c \
     src/core/lib/security/credentials/composite/composite_credentials.c \
@@ -3327,8 +3331,8 @@
     src/core/tsi/ssl_transport_security.c \
     src/core/tsi/transport_security.c \
     src/core/ext/transport/chttp2/client/chttp2_connector.c \
-    src/core/ext/load_reporting/load_reporting.c \
-    src/core/ext/load_reporting/load_reporting_filter.c \
+    src/core/ext/filters/load_reporting/load_reporting.c \
+    src/core/ext/filters/load_reporting/load_reporting_filter.c \
     src/core/plugin_registry/grpc_cronet_plugin_registry.c \
 
 PUBLIC_HEADERS_C += \
@@ -3448,7 +3452,6 @@
     src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/max_age_filter.c \
     src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
@@ -3681,7 +3684,6 @@
     src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/max_age_filter.c \
     src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
@@ -3822,42 +3824,42 @@
     src/core/ext/transport/chttp2/client/insecure/channel_create.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
     src/core/ext/transport/chttp2/client/chttp2_connector.c \
-    src/core/ext/client_channel/channel_connectivity.c \
-    src/core/ext/client_channel/client_channel.c \
-    src/core/ext/client_channel/client_channel_factory.c \
-    src/core/ext/client_channel/client_channel_plugin.c \
-    src/core/ext/client_channel/connector.c \
-    src/core/ext/client_channel/http_connect_handshaker.c \
-    src/core/ext/client_channel/http_proxy.c \
-    src/core/ext/client_channel/lb_policy.c \
-    src/core/ext/client_channel/lb_policy_factory.c \
-    src/core/ext/client_channel/lb_policy_registry.c \
-    src/core/ext/client_channel/parse_address.c \
-    src/core/ext/client_channel/proxy_mapper.c \
-    src/core/ext/client_channel/proxy_mapper_registry.c \
-    src/core/ext/client_channel/resolver.c \
-    src/core/ext/client_channel/resolver_factory.c \
-    src/core/ext/client_channel/resolver_registry.c \
-    src/core/ext/client_channel/retry_throttle.c \
-    src/core/ext/client_channel/subchannel.c \
-    src/core/ext/client_channel/subchannel_index.c \
-    src/core/ext/client_channel/uri_parser.c \
-    src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c \
-    src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
-    src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c \
-    src/core/ext/resolver/dns/native/dns_resolver.c \
-    src/core/ext/resolver/sockaddr/sockaddr_resolver.c \
-    src/core/ext/load_reporting/load_reporting.c \
-    src/core/ext/load_reporting/load_reporting_filter.c \
-    src/core/ext/lb_policy/grpclb/grpclb.c \
-    src/core/ext/lb_policy/grpclb/grpclb_channel.c \
-    src/core/ext/lb_policy/grpclb/load_balancer_api.c \
-    src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
+    src/core/ext/filters/client_channel/channel_connectivity.c \
+    src/core/ext/filters/client_channel/client_channel.c \
+    src/core/ext/filters/client_channel/client_channel_factory.c \
+    src/core/ext/filters/client_channel/client_channel_plugin.c \
+    src/core/ext/filters/client_channel/connector.c \
+    src/core/ext/filters/client_channel/http_connect_handshaker.c \
+    src/core/ext/filters/client_channel/http_proxy.c \
+    src/core/ext/filters/client_channel/lb_policy.c \
+    src/core/ext/filters/client_channel/lb_policy_factory.c \
+    src/core/ext/filters/client_channel/lb_policy_registry.c \
+    src/core/ext/filters/client_channel/parse_address.c \
+    src/core/ext/filters/client_channel/proxy_mapper.c \
+    src/core/ext/filters/client_channel/proxy_mapper_registry.c \
+    src/core/ext/filters/client_channel/resolver.c \
+    src/core/ext/filters/client_channel/resolver_factory.c \
+    src/core/ext/filters/client_channel/resolver_registry.c \
+    src/core/ext/filters/client_channel/retry_throttle.c \
+    src/core/ext/filters/client_channel/subchannel.c \
+    src/core/ext/filters/client_channel/subchannel_index.c \
+    src/core/ext/filters/client_channel/uri_parser.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c \
+    src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c \
+    src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c \
+    src/core/ext/filters/load_reporting/load_reporting.c \
+    src/core/ext/filters/load_reporting/load_reporting_filter.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
     third_party/nanopb/pb_common.c \
     third_party/nanopb/pb_decode.c \
     third_party/nanopb/pb_encode.c \
-    src/core/ext/lb_policy/pick_first/pick_first.c \
-    src/core/ext/lb_policy/round_robin/round_robin.c \
+    src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c \
+    src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c \
     src/core/ext/census/base_resources.c \
     src/core/ext/census/context.c \
     src/core/ext/census/gen/census.pb.c \
@@ -3872,6 +3874,7 @@
     src/core/ext/census/resource.c \
     src/core/ext/census/trace_context.c \
     src/core/ext/census/tracing.c \
+    src/core/ext/filters/max_age/max_age_filter.c \
     src/core/plugin_registry/grpc_unsecure_plugin_registry.c \
 
 PUBLIC_HEADERS_C += \
@@ -4074,7 +4077,6 @@
     src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/max_age_filter.c \
     src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
@@ -4413,7 +4415,6 @@
     src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/max_age_filter.c \
     src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
@@ -4555,26 +4556,26 @@
     src/core/ext/transport/chttp2/transport/varint.c \
     src/core/ext/transport/chttp2/transport/writing.c \
     src/core/ext/transport/chttp2/alpn/alpn.c \
-    src/core/ext/client_channel/channel_connectivity.c \
-    src/core/ext/client_channel/client_channel.c \
-    src/core/ext/client_channel/client_channel_factory.c \
-    src/core/ext/client_channel/client_channel_plugin.c \
-    src/core/ext/client_channel/connector.c \
-    src/core/ext/client_channel/http_connect_handshaker.c \
-    src/core/ext/client_channel/http_proxy.c \
-    src/core/ext/client_channel/lb_policy.c \
-    src/core/ext/client_channel/lb_policy_factory.c \
-    src/core/ext/client_channel/lb_policy_registry.c \
-    src/core/ext/client_channel/parse_address.c \
-    src/core/ext/client_channel/proxy_mapper.c \
-    src/core/ext/client_channel/proxy_mapper_registry.c \
-    src/core/ext/client_channel/resolver.c \
-    src/core/ext/client_channel/resolver_factory.c \
-    src/core/ext/client_channel/resolver_registry.c \
-    src/core/ext/client_channel/retry_throttle.c \
-    src/core/ext/client_channel/subchannel.c \
-    src/core/ext/client_channel/subchannel_index.c \
-    src/core/ext/client_channel/uri_parser.c \
+    src/core/ext/filters/client_channel/channel_connectivity.c \
+    src/core/ext/filters/client_channel/client_channel.c \
+    src/core/ext/filters/client_channel/client_channel_factory.c \
+    src/core/ext/filters/client_channel/client_channel_plugin.c \
+    src/core/ext/filters/client_channel/connector.c \
+    src/core/ext/filters/client_channel/http_connect_handshaker.c \
+    src/core/ext/filters/client_channel/http_proxy.c \
+    src/core/ext/filters/client_channel/lb_policy.c \
+    src/core/ext/filters/client_channel/lb_policy_factory.c \
+    src/core/ext/filters/client_channel/lb_policy_registry.c \
+    src/core/ext/filters/client_channel/parse_address.c \
+    src/core/ext/filters/client_channel/proxy_mapper.c \
+    src/core/ext/filters/client_channel/proxy_mapper_registry.c \
+    src/core/ext/filters/client_channel/resolver.c \
+    src/core/ext/filters/client_channel/resolver_factory.c \
+    src/core/ext/filters/client_channel/resolver_registry.c \
+    src/core/ext/filters/client_channel/retry_throttle.c \
+    src/core/ext/filters/client_channel/subchannel.c \
+    src/core/ext/filters/client_channel/subchannel_index.c \
+    src/core/ext/filters/client_channel/uri_parser.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
     src/core/ext/transport/chttp2/server/chttp2_server.c \
@@ -5104,7 +5105,6 @@
     src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/max_age_filter.c \
     src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
@@ -8226,6 +8226,7 @@
     test/core/end2end/end2end_test_utils.c \
     test/core/end2end/tests/authority_not_supported.c \
     test/core/end2end/tests/bad_hostname.c \
+    test/core/end2end/tests/bad_ping.c \
     test/core/end2end/tests/binary_metadata.c \
     test/core/end2end/tests/call_creds.c \
     test/core/end2end/tests/cancel_after_accept.c \
@@ -8318,6 +8319,7 @@
     test/core/end2end/end2end_test_utils.c \
     test/core/end2end/tests/authority_not_supported.c \
     test/core/end2end/tests/bad_hostname.c \
+    test/core/end2end/tests/bad_ping.c \
     test/core/end2end/tests/binary_metadata.c \
     test/core/end2end/tests/cancel_after_accept.c \
     test/core/end2end/tests/cancel_after_client_done.c \
@@ -13363,6 +13365,50 @@
 endif
 
 
+BM_CQ_MULTIPLE_THREADS_SRC = \
+    test/cpp/microbenchmarks/bm_cq_multiple_threads.cc \
+
+BM_CQ_MULTIPLE_THREADS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BM_CQ_MULTIPLE_THREADS_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/bm_cq_multiple_threads: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/bm_cq_multiple_threads: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/bm_cq_multiple_threads: $(PROTOBUF_DEP) $(BM_CQ_MULTIPLE_THREADS_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(BM_CQ_MULTIPLE_THREADS_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads
+
+endif
+
+endif
+
+$(BM_CQ_MULTIPLE_THREADS_OBJS): CPPFLAGS += -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX
+$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/bm_cq_multiple_threads.o:  $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_bm_cq_multiple_threads: $(BM_CQ_MULTIPLE_THREADS_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(BM_CQ_MULTIPLE_THREADS_OBJS:.o=.dep)
+endif
+endif
+
+
 BM_ERROR_SRC = \
     test/cpp/microbenchmarks/bm_error.cc \
 
@@ -19176,7 +19222,7 @@
 # This is to ensure the embedded OpenSSL is built beforehand, properly
 # installing headers to their final destination on the drive. We need this
 # otherwise parallel compilation will fail if a source is compiled first.
-src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c: $(OPENSSL_DEP)
+src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c: $(OPENSSL_DEP)
 src/core/ext/transport/chttp2/client/secure/secure_channel_create.c: $(OPENSSL_DEP)
 src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c: $(OPENSSL_DEP)
 src/core/ext/transport/cronet/client/secure/cronet_channel_create.c: $(OPENSSL_DEP)
diff --git a/README.md b/README.md
index adcfdf1..e6d8792 100644
--- a/README.md
+++ b/README.md
@@ -27,14 +27,14 @@
 
 | Language                | Source                              | Status  |
 |-------------------------|-------------------------------------|---------|
-| Shared C [core library] | [src/core] (src/core)               | 1.0     |
-| C++                     | [src/cpp] (src/cpp)                 | 1.0     |
-| Ruby                    | [src/ruby] (src/ruby)               | 1.0     |
-| NodeJS                  | [src/node] (src/node)               | 1.0     |
-| Python                  | [src/python] (src/python)           | 1.0     |
-| PHP                     | [src/php] (src/php)                 | 1.0     |
-| C#                      | [src/csharp] (src/csharp)           | 1.0     |
-| Objective-C             | [src/objective-c] (src/objective-c) | 1.0     |
+| Shared C [core library] | [src/core](src/core)                | 1.0     |
+| C++                     | [src/cpp](src/cpp)                  | 1.0     |
+| Ruby                    | [src/ruby](src/ruby)                | 1.0     |
+| NodeJS                  | [src/node](src/node)                | 1.0     |
+| Python                  | [src/python](src/python)            | 1.0     |
+| PHP                     | [src/php](src/php)                  | 1.0     |
+| C#                      | [src/csharp](src/csharp)            | 1.0     |
+| Objective-C             | [src/objective-c](src/objective-c)  | 1.0     |
 
 <small>
 Java source code is in the [grpc-java](http://github.com/grpc/grpc-java) repository.
diff --git a/binding.gyp b/binding.gyp
index cd2de83..3444fa5 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -45,9 +45,42 @@
     # Some Node installations use the system installation of OpenSSL, and on
     # some systems, the system OpenSSL still does not have ALPN support. This
     # will let users recompile gRPC to work without ALPN.
-    'grpc_alpn%': 'true'
+    'grpc_alpn%': 'true',
+    # Indicates that the library should be built with gcov.
+    'grpc_gcov%': 'false'
   },
   'target_defaults': {
+    'configurations': {
+      'Release': {
+        'cflags': [
+            '-O2',
+        ],
+        'defines': [
+            'NDEBUG',
+        ],
+      },
+      'Debug': {
+        'cflags': [
+            '-O0',
+        ],
+        'defines': [
+            '_DEBUG',
+            'DEBUG',
+        ],
+      },
+    },
+    'cflags': [
+        '-g',
+        '-Wall',
+        '-Wextra',
+        '-Werror',
+        '-Wno-long-long',
+        '-Wno-unused-parameter',
+        '-DOSATOMIC_USE_INLINED=1',
+    ],
+    'ldflags': [
+        '-g',
+    ],
     'include_dirs': [
       '.',
       'include'
@@ -64,6 +97,24 @@
           'GRPC_UV'
         ]
       }],
+      ['grpc_gcov=="true"', {
+        'cflags': [
+            '-O0',
+            '-fprofile-arcs',
+            '-ftest-coverage',
+            '-Wno-return-type',
+        ],
+        'defines': [
+            '_DEBUG',
+            'DEBUG',
+            'GPR_GCOV',
+        ],
+        'ldflags': [
+            '-fprofile-arcs',
+            '-ftest-coverage',
+            '-rdynamic',
+        ],
+      }],
       ['OS!="win" and runtime=="electron"', {
         "defines": [
           'OPENSSL_NO_THREADS'
@@ -126,26 +177,9 @@
           "ws2_32"
         ]
       }, { # OS != "win"
-        'variables': {
-          'config': '<!(echo $CONFIG)',
-        },
         'include_dirs': [
           '<(node_root_dir)/deps/zlib',
-          '<(node_root_dir)/deps/cares/include',
-        ],
-        'conditions': [
-          ['config=="gcov"', {
-            'cflags': [
-              '-ftest-coverage',
-              '-fprofile-arcs',
-              '-O0'
-            ],
-            'ldflags': [
-              '-ftest-coverage',
-              '-fprofile-arcs'
-            ]
-          }
-         ]
+          '<(node_root_dir)/deps/cares/include'
         ]
       }]
     ]
@@ -626,7 +660,6 @@
         'src/core/lib/channel/handshaker_registry.c',
         'src/core/lib/channel/http_client_filter.c',
         'src/core/lib/channel/http_server_filter.c',
-        'src/core/lib/channel/max_age_filter.c',
         'src/core/lib/channel/message_size_filter.c',
         'src/core/lib/compression/compression.c',
         'src/core/lib/compression/message_compress.c',
@@ -791,47 +824,47 @@
         'src/core/tsi/transport_security.c',
         'src/core/ext/transport/chttp2/server/chttp2_server.c',
         'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
-        'src/core/ext/client_channel/channel_connectivity.c',
-        'src/core/ext/client_channel/client_channel.c',
-        'src/core/ext/client_channel/client_channel_factory.c',
-        'src/core/ext/client_channel/client_channel_plugin.c',
-        'src/core/ext/client_channel/connector.c',
-        'src/core/ext/client_channel/http_connect_handshaker.c',
-        'src/core/ext/client_channel/http_proxy.c',
-        'src/core/ext/client_channel/lb_policy.c',
-        'src/core/ext/client_channel/lb_policy_factory.c',
-        'src/core/ext/client_channel/lb_policy_registry.c',
-        'src/core/ext/client_channel/parse_address.c',
-        'src/core/ext/client_channel/proxy_mapper.c',
-        'src/core/ext/client_channel/proxy_mapper_registry.c',
-        'src/core/ext/client_channel/resolver.c',
-        'src/core/ext/client_channel/resolver_factory.c',
-        'src/core/ext/client_channel/resolver_registry.c',
-        'src/core/ext/client_channel/retry_throttle.c',
-        'src/core/ext/client_channel/subchannel.c',
-        'src/core/ext/client_channel/subchannel_index.c',
-        'src/core/ext/client_channel/uri_parser.c',
+        'src/core/ext/filters/client_channel/channel_connectivity.c',
+        'src/core/ext/filters/client_channel/client_channel.c',
+        'src/core/ext/filters/client_channel/client_channel_factory.c',
+        'src/core/ext/filters/client_channel/client_channel_plugin.c',
+        'src/core/ext/filters/client_channel/connector.c',
+        'src/core/ext/filters/client_channel/http_connect_handshaker.c',
+        'src/core/ext/filters/client_channel/http_proxy.c',
+        'src/core/ext/filters/client_channel/lb_policy.c',
+        'src/core/ext/filters/client_channel/lb_policy_factory.c',
+        'src/core/ext/filters/client_channel/lb_policy_registry.c',
+        'src/core/ext/filters/client_channel/parse_address.c',
+        'src/core/ext/filters/client_channel/proxy_mapper.c',
+        'src/core/ext/filters/client_channel/proxy_mapper_registry.c',
+        'src/core/ext/filters/client_channel/resolver.c',
+        'src/core/ext/filters/client_channel/resolver_factory.c',
+        'src/core/ext/filters/client_channel/resolver_registry.c',
+        'src/core/ext/filters/client_channel/retry_throttle.c',
+        'src/core/ext/filters/client_channel/subchannel.c',
+        'src/core/ext/filters/client_channel/subchannel_index.c',
+        'src/core/ext/filters/client_channel/uri_parser.c',
         'src/core/ext/transport/chttp2/client/chttp2_connector.c',
         'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
         'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
         'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
         'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
-        'src/core/ext/lb_policy/grpclb/grpclb.c',
-        'src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c',
-        'src/core/ext/lb_policy/grpclb/load_balancer_api.c',
-        'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
+        'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c',
+        'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c',
+        'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c',
+        'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
         'third_party/nanopb/pb_common.c',
         'third_party/nanopb/pb_decode.c',
         'third_party/nanopb/pb_encode.c',
-        'src/core/ext/lb_policy/pick_first/pick_first.c',
-        'src/core/ext/lb_policy/round_robin/round_robin.c',
-        'src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c',
-        'src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
-        'src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c',
-        'src/core/ext/resolver/dns/native/dns_resolver.c',
-        'src/core/ext/resolver/sockaddr/sockaddr_resolver.c',
-        'src/core/ext/load_reporting/load_reporting.c',
-        'src/core/ext/load_reporting/load_reporting_filter.c',
+        'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c',
+        'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c',
+        'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c',
+        'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
+        'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c',
+        'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c',
+        'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c',
+        'src/core/ext/filters/load_reporting/load_reporting.c',
+        'src/core/ext/filters/load_reporting/load_reporting_filter.c',
         'src/core/ext/census/base_resources.c',
         'src/core/ext/census/context.c',
         'src/core/ext/census/gen/census.pb.c',
@@ -846,6 +879,7 @@
         'src/core/ext/census/resource.c',
         'src/core/ext/census/trace_context.c',
         'src/core/ext/census/tracing.c',
+        'src/core/ext/filters/max_age/max_age_filter.c',
         'src/core/plugin_registry/grpc_plugin_registry.c',
       ],
       "conditions": [
@@ -862,16 +896,10 @@
       ],
       'cflags': [
         '-std=c++11',
-        '-Wall',
         '-pthread',
-        '-g',
         '-zdefs',
-        '-Werror',
         '-Wno-error=deprecated-declarations'
       ],
-      'ldflags': [
-        '-g'
-      ],
       "conditions": [
         ['OS=="win" or runtime=="electron"', {
           'dependencies': [
diff --git a/build.yaml b/build.yaml
index 8aff168..6fbc8d9 100644
--- a/build.yaml
+++ b/build.yaml
@@ -185,7 +185,6 @@
   - src/core/lib/channel/handshaker_registry.h
   - src/core/lib/channel/http_client_filter.h
   - src/core/lib/channel/http_server_filter.h
-  - src/core/lib/channel/max_age_filter.h
   - src/core/lib/channel/message_size_filter.h
   - src/core/lib/compression/algorithm_metadata.h
   - src/core/lib/compression/message_compress.h
@@ -296,7 +295,6 @@
   - src/core/lib/channel/handshaker_registry.c
   - src/core/lib/channel/http_client_filter.c
   - src/core/lib/channel/http_server_filter.c
-  - src/core/lib/channel/max_age_filter.c
   - src/core/lib/channel/message_size_filter.c
   - src/core/lib/compression/compression.c
   - src/core/lib/compression/message_compress.c
@@ -416,45 +414,45 @@
   - grpc_codegen
 - name: grpc_client_channel
   headers:
-  - src/core/ext/client_channel/client_channel.h
-  - src/core/ext/client_channel/client_channel_factory.h
-  - src/core/ext/client_channel/connector.h
-  - src/core/ext/client_channel/http_connect_handshaker.h
-  - src/core/ext/client_channel/http_proxy.h
-  - src/core/ext/client_channel/lb_policy.h
-  - src/core/ext/client_channel/lb_policy_factory.h
-  - src/core/ext/client_channel/lb_policy_registry.h
-  - src/core/ext/client_channel/parse_address.h
-  - src/core/ext/client_channel/proxy_mapper.h
-  - src/core/ext/client_channel/proxy_mapper_registry.h
-  - src/core/ext/client_channel/resolver.h
-  - src/core/ext/client_channel/resolver_factory.h
-  - src/core/ext/client_channel/resolver_registry.h
-  - src/core/ext/client_channel/retry_throttle.h
-  - src/core/ext/client_channel/subchannel.h
-  - src/core/ext/client_channel/subchannel_index.h
-  - src/core/ext/client_channel/uri_parser.h
+  - src/core/ext/filters/client_channel/client_channel.h
+  - src/core/ext/filters/client_channel/client_channel_factory.h
+  - src/core/ext/filters/client_channel/connector.h
+  - src/core/ext/filters/client_channel/http_connect_handshaker.h
+  - src/core/ext/filters/client_channel/http_proxy.h
+  - src/core/ext/filters/client_channel/lb_policy.h
+  - src/core/ext/filters/client_channel/lb_policy_factory.h
+  - src/core/ext/filters/client_channel/lb_policy_registry.h
+  - src/core/ext/filters/client_channel/parse_address.h
+  - src/core/ext/filters/client_channel/proxy_mapper.h
+  - src/core/ext/filters/client_channel/proxy_mapper_registry.h
+  - src/core/ext/filters/client_channel/resolver.h
+  - src/core/ext/filters/client_channel/resolver_factory.h
+  - src/core/ext/filters/client_channel/resolver_registry.h
+  - src/core/ext/filters/client_channel/retry_throttle.h
+  - src/core/ext/filters/client_channel/subchannel.h
+  - src/core/ext/filters/client_channel/subchannel_index.h
+  - src/core/ext/filters/client_channel/uri_parser.h
   src:
-  - src/core/ext/client_channel/channel_connectivity.c
-  - src/core/ext/client_channel/client_channel.c
-  - src/core/ext/client_channel/client_channel_factory.c
-  - src/core/ext/client_channel/client_channel_plugin.c
-  - src/core/ext/client_channel/connector.c
-  - src/core/ext/client_channel/http_connect_handshaker.c
-  - src/core/ext/client_channel/http_proxy.c
-  - src/core/ext/client_channel/lb_policy.c
-  - src/core/ext/client_channel/lb_policy_factory.c
-  - src/core/ext/client_channel/lb_policy_registry.c
-  - src/core/ext/client_channel/parse_address.c
-  - src/core/ext/client_channel/proxy_mapper.c
-  - src/core/ext/client_channel/proxy_mapper_registry.c
-  - src/core/ext/client_channel/resolver.c
-  - src/core/ext/client_channel/resolver_factory.c
-  - src/core/ext/client_channel/resolver_registry.c
-  - src/core/ext/client_channel/retry_throttle.c
-  - src/core/ext/client_channel/subchannel.c
-  - src/core/ext/client_channel/subchannel_index.c
-  - src/core/ext/client_channel/uri_parser.c
+  - src/core/ext/filters/client_channel/channel_connectivity.c
+  - src/core/ext/filters/client_channel/client_channel.c
+  - src/core/ext/filters/client_channel/client_channel_factory.c
+  - src/core/ext/filters/client_channel/client_channel_plugin.c
+  - src/core/ext/filters/client_channel/connector.c
+  - src/core/ext/filters/client_channel/http_connect_handshaker.c
+  - src/core/ext/filters/client_channel/http_proxy.c
+  - src/core/ext/filters/client_channel/lb_policy.c
+  - src/core/ext/filters/client_channel/lb_policy_factory.c
+  - src/core/ext/filters/client_channel/lb_policy_registry.c
+  - src/core/ext/filters/client_channel/parse_address.c
+  - src/core/ext/filters/client_channel/proxy_mapper.c
+  - src/core/ext/filters/client_channel/proxy_mapper_registry.c
+  - src/core/ext/filters/client_channel/resolver.c
+  - src/core/ext/filters/client_channel/resolver_factory.c
+  - src/core/ext/filters/client_channel/resolver_registry.c
+  - src/core/ext/filters/client_channel/retry_throttle.c
+  - src/core/ext/filters/client_channel/subchannel.c
+  - src/core/ext/filters/client_channel/subchannel_index.c
+  - src/core/ext/filters/client_channel/uri_parser.c
   plugin: grpc_client_channel
   uses:
   - grpc_base
@@ -472,15 +470,15 @@
   - gpr_codegen
 - name: grpc_lb_policy_grpclb
   headers:
-  - src/core/ext/lb_policy/grpclb/grpclb.h
-  - src/core/ext/lb_policy/grpclb/grpclb_channel.h
-  - src/core/ext/lb_policy/grpclb/load_balancer_api.h
-  - src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
   src:
-  - src/core/ext/lb_policy/grpclb/grpclb.c
-  - src/core/ext/lb_policy/grpclb/grpclb_channel.c
-  - src/core/ext/lb_policy/grpclb/load_balancer_api.c
-  - src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.c
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
   plugin: grpc_lb_policy_grpclb
   uses:
   - grpc_base
@@ -488,15 +486,15 @@
   - nanopb
 - name: grpc_lb_policy_grpclb_secure
   headers:
-  - src/core/ext/lb_policy/grpclb/grpclb.h
-  - src/core/ext/lb_policy/grpclb/grpclb_channel.h
-  - src/core/ext/lb_policy/grpclb/load_balancer_api.h
-  - src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
   src:
-  - src/core/ext/lb_policy/grpclb/grpclb.c
-  - src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c
-  - src/core/ext/lb_policy/grpclb/load_balancer_api.c
-  - src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c
+  - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
   plugin: grpc_lb_policy_grpclb
   uses:
   - grpc_base
@@ -505,50 +503,58 @@
   - nanopb
 - name: grpc_lb_policy_pick_first
   src:
-  - src/core/ext/lb_policy/pick_first/pick_first.c
+  - src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c
   plugin: grpc_lb_policy_pick_first
   uses:
   - grpc_base
   - grpc_client_channel
 - name: grpc_lb_policy_round_robin
   src:
-  - src/core/ext/lb_policy/round_robin/round_robin.c
+  - src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c
   plugin: grpc_lb_policy_round_robin
   uses:
   - grpc_base
   - grpc_client_channel
 - name: grpc_load_reporting
   headers:
-  - src/core/ext/load_reporting/load_reporting.h
-  - src/core/ext/load_reporting/load_reporting_filter.h
+  - src/core/ext/filters/load_reporting/load_reporting.h
+  - src/core/ext/filters/load_reporting/load_reporting_filter.h
   src:
-  - src/core/ext/load_reporting/load_reporting.c
-  - src/core/ext/load_reporting/load_reporting_filter.c
+  - src/core/ext/filters/load_reporting/load_reporting.c
+  - src/core/ext/filters/load_reporting/load_reporting_filter.c
   plugin: grpc_load_reporting_plugin
   uses:
   - grpc_base
+- name: grpc_max_age_filter
+  headers:
+  - src/core/ext/filters/max_age/max_age_filter.h
+  src:
+  - src/core/ext/filters/max_age/max_age_filter.c
+  plugin: grpc_max_age_filter
+  uses:
+  - grpc_base
 - name: grpc_resolver_dns_ares
   headers:
-  - src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h
-  - src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h
+  - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
+  - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
   src:
-  - src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c
-  - src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
-  - src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c
+  - src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
+  - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
+  - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
   plugin: grpc_resolver_dns_ares
   uses:
   - grpc_base
   - grpc_client_channel
 - name: grpc_resolver_dns_native
   src:
-  - src/core/ext/resolver/dns/native/dns_resolver.c
+  - src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c
   plugin: grpc_resolver_dns_native
   uses:
   - grpc_base
   - grpc_client_channel
 - name: grpc_resolver_sockaddr
   src:
-  - src/core/ext/resolver/sockaddr/sockaddr_resolver.c
+  - src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c
   plugin: grpc_resolver_sockaddr
   uses:
   - grpc_base
@@ -990,6 +996,7 @@
   - grpc_load_reporting
   - grpc_secure
   - census
+  - grpc_max_age_filter
   generate_plugin_registry: true
   secure: true
   vs_packages:
@@ -1086,6 +1093,7 @@
   - grpc_lb_policy_pick_first
   - grpc_lb_policy_round_robin
   - census
+  - grpc_max_age_filter
   generate_plugin_registry: true
   secure: false
   vs_project_guid: '{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}'
@@ -1299,11 +1307,15 @@
   - src/compiler/objective_c_generator_helpers.h
   - src/compiler/php_generator.h
   - src/compiler/php_generator_helpers.h
+  - src/compiler/protobuf_plugin.h
   - src/compiler/python_generator.h
+  - src/compiler/python_generator_helpers.h
+  - src/compiler/python_private_generator.h
   - src/compiler/ruby_generator.h
   - src/compiler/ruby_generator_helpers-inl.h
   - src/compiler/ruby_generator_map-inl.h
   - src/compiler/ruby_generator_string-inl.h
+  - src/compiler/schema_interface.h
   src:
   - src/compiler/cpp_generator.cc
   - src/compiler/csharp_generator.cc
@@ -3205,6 +3217,27 @@
   - mac
   - linux
   - posix
+- name: bm_cq_multiple_threads
+  build: test
+  language: c++
+  src:
+  - test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
+  deps:
+  - grpc_benchmark
+  - benchmark
+  - grpc++_test_util
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
+  args:
+  - --benchmark_min_time=0
+  defaults: benchmark
+  platforms:
+  - mac
+  - linux
+  - posix
 - name: bm_error
   build: test
   language: c++
diff --git a/cmake/msvc_static_runtime.cmake b/cmake/msvc_static_runtime.cmake
index 5a31ab3..fc6d1d6 100644
--- a/cmake/msvc_static_runtime.cmake
+++ b/cmake/msvc_static_runtime.cmake
@@ -3,6 +3,8 @@
 if(gRPC_MSVC_STATIC_RUNTIME)
   # switch from dynamic to static linking of msvcrt
   foreach(flag_var
+    CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
+    CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
     CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
     CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
 
diff --git a/config.m4 b/config.m4
index 6e6a65a..2846781 100644
--- a/config.m4
+++ b/config.m4
@@ -94,7 +94,6 @@
     src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
-    src/core/lib/channel/max_age_filter.c \
     src/core/lib/channel/message_size_filter.c \
     src/core/lib/compression/compression.c \
     src/core/lib/compression/message_compress.c \
@@ -259,47 +258,47 @@
     src/core/tsi/transport_security.c \
     src/core/ext/transport/chttp2/server/chttp2_server.c \
     src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
-    src/core/ext/client_channel/channel_connectivity.c \
-    src/core/ext/client_channel/client_channel.c \
-    src/core/ext/client_channel/client_channel_factory.c \
-    src/core/ext/client_channel/client_channel_plugin.c \
-    src/core/ext/client_channel/connector.c \
-    src/core/ext/client_channel/http_connect_handshaker.c \
-    src/core/ext/client_channel/http_proxy.c \
-    src/core/ext/client_channel/lb_policy.c \
-    src/core/ext/client_channel/lb_policy_factory.c \
-    src/core/ext/client_channel/lb_policy_registry.c \
-    src/core/ext/client_channel/parse_address.c \
-    src/core/ext/client_channel/proxy_mapper.c \
-    src/core/ext/client_channel/proxy_mapper_registry.c \
-    src/core/ext/client_channel/resolver.c \
-    src/core/ext/client_channel/resolver_factory.c \
-    src/core/ext/client_channel/resolver_registry.c \
-    src/core/ext/client_channel/retry_throttle.c \
-    src/core/ext/client_channel/subchannel.c \
-    src/core/ext/client_channel/subchannel_index.c \
-    src/core/ext/client_channel/uri_parser.c \
+    src/core/ext/filters/client_channel/channel_connectivity.c \
+    src/core/ext/filters/client_channel/client_channel.c \
+    src/core/ext/filters/client_channel/client_channel_factory.c \
+    src/core/ext/filters/client_channel/client_channel_plugin.c \
+    src/core/ext/filters/client_channel/connector.c \
+    src/core/ext/filters/client_channel/http_connect_handshaker.c \
+    src/core/ext/filters/client_channel/http_proxy.c \
+    src/core/ext/filters/client_channel/lb_policy.c \
+    src/core/ext/filters/client_channel/lb_policy_factory.c \
+    src/core/ext/filters/client_channel/lb_policy_registry.c \
+    src/core/ext/filters/client_channel/parse_address.c \
+    src/core/ext/filters/client_channel/proxy_mapper.c \
+    src/core/ext/filters/client_channel/proxy_mapper_registry.c \
+    src/core/ext/filters/client_channel/resolver.c \
+    src/core/ext/filters/client_channel/resolver_factory.c \
+    src/core/ext/filters/client_channel/resolver_registry.c \
+    src/core/ext/filters/client_channel/retry_throttle.c \
+    src/core/ext/filters/client_channel/subchannel.c \
+    src/core/ext/filters/client_channel/subchannel_index.c \
+    src/core/ext/filters/client_channel/uri_parser.c \
     src/core/ext/transport/chttp2/client/chttp2_connector.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
-    src/core/ext/lb_policy/grpclb/grpclb.c \
-    src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c \
-    src/core/ext/lb_policy/grpclb/load_balancer_api.c \
-    src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c \
+    src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
     third_party/nanopb/pb_common.c \
     third_party/nanopb/pb_decode.c \
     third_party/nanopb/pb_encode.c \
-    src/core/ext/lb_policy/pick_first/pick_first.c \
-    src/core/ext/lb_policy/round_robin/round_robin.c \
-    src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c \
-    src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
-    src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c \
-    src/core/ext/resolver/dns/native/dns_resolver.c \
-    src/core/ext/resolver/sockaddr/sockaddr_resolver.c \
-    src/core/ext/load_reporting/load_reporting.c \
-    src/core/ext/load_reporting/load_reporting_filter.c \
+    src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c \
+    src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c \
+    src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c \
+    src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c \
+    src/core/ext/filters/load_reporting/load_reporting.c \
+    src/core/ext/filters/load_reporting/load_reporting_filter.c \
     src/core/ext/census/base_resources.c \
     src/core/ext/census/context.c \
     src/core/ext/census/gen/census.pb.c \
@@ -314,6 +313,7 @@
     src/core/ext/census/resource.c \
     src/core/ext/census/trace_context.c \
     src/core/ext/census/tracing.c \
+    src/core/ext/filters/max_age/max_age_filter.c \
     src/core/plugin_registry/grpc_plugin_registry.c \
     src/boringssl/err_data.c \
     third_party/boringssl/crypto/aes/aes.c \
@@ -629,15 +629,16 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/boringssl)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/census)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/census/gen)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/client_channel)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/lb_policy/grpclb)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/lb_policy/pick_first)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/lb_policy/round_robin)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/load_reporting)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/resolver/dns/c_ares)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/resolver/dns/native)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/resolver/sockaddr)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/pick_first)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/round_robin)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/c_ares)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/native)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/sockaddr)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/load_reporting)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/max_age)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/alpn)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client/insecure)
diff --git a/doc/PROTOCOL-WEB.md b/doc/PROTOCOL-WEB.md
index 5f01af3..6bb2808 100644
--- a/doc/PROTOCOL-WEB.md
+++ b/doc/PROTOCOL-WEB.md
@@ -83,7 +83,8 @@
 
 User Agent
 
-* U-A: grpc-web-javascript
+* Do NOT use User-Agent header (which is to be set by browsers, by default)
+* Use X-User-Agent: grpc-web-javascript/0.1 (follow the same format as specified in [gRPC over HTTP2](http://www.grpc.io/docs/guides/wire.html))
 
 ---
 
diff --git a/doc/environment_variables.md b/doc/environment_variables.md
index 513936d..47efb3a 100644
--- a/doc/environment_variables.md
+++ b/doc/environment_variables.md
@@ -55,6 +55,7 @@
   - queue_timeout
   - server_channel - lightweight trace of significant server channel events
   - secure_endpoint - traces bytes flowing through encrypted channels
+  - timer - timers (alarms) in the grpc internals
   - transport_security - traces metadata about secure channel establishment
   - tcp - traces bytes in and out of a channel
 
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index d750a5b..83c19af 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -267,7 +267,6 @@
                       'src/core/lib/channel/handshaker_registry.h',
                       'src/core/lib/channel/http_client_filter.h',
                       'src/core/lib/channel/http_server_filter.h',
-                      'src/core/lib/channel/max_age_filter.h',
                       'src/core/lib/channel/message_size_filter.h',
                       'src/core/lib/compression/algorithm_metadata.h',
                       'src/core/lib/compression/message_compress.h',
@@ -410,37 +409,37 @@
                       'src/core/tsi/transport_security.h',
                       'src/core/tsi/transport_security_interface.h',
                       'src/core/ext/transport/chttp2/server/chttp2_server.h',
-                      'src/core/ext/client_channel/client_channel.h',
-                      'src/core/ext/client_channel/client_channel_factory.h',
-                      'src/core/ext/client_channel/connector.h',
-                      'src/core/ext/client_channel/http_connect_handshaker.h',
-                      'src/core/ext/client_channel/http_proxy.h',
-                      'src/core/ext/client_channel/lb_policy.h',
-                      'src/core/ext/client_channel/lb_policy_factory.h',
-                      'src/core/ext/client_channel/lb_policy_registry.h',
-                      'src/core/ext/client_channel/parse_address.h',
-                      'src/core/ext/client_channel/proxy_mapper.h',
-                      'src/core/ext/client_channel/proxy_mapper_registry.h',
-                      'src/core/ext/client_channel/resolver.h',
-                      'src/core/ext/client_channel/resolver_factory.h',
-                      'src/core/ext/client_channel/resolver_registry.h',
-                      'src/core/ext/client_channel/retry_throttle.h',
-                      'src/core/ext/client_channel/subchannel.h',
-                      'src/core/ext/client_channel/subchannel_index.h',
-                      'src/core/ext/client_channel/uri_parser.h',
+                      'src/core/ext/filters/client_channel/client_channel.h',
+                      'src/core/ext/filters/client_channel/client_channel_factory.h',
+                      'src/core/ext/filters/client_channel/connector.h',
+                      'src/core/ext/filters/client_channel/http_connect_handshaker.h',
+                      'src/core/ext/filters/client_channel/http_proxy.h',
+                      'src/core/ext/filters/client_channel/lb_policy.h',
+                      'src/core/ext/filters/client_channel/lb_policy_factory.h',
+                      'src/core/ext/filters/client_channel/lb_policy_registry.h',
+                      'src/core/ext/filters/client_channel/parse_address.h',
+                      'src/core/ext/filters/client_channel/proxy_mapper.h',
+                      'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
+                      'src/core/ext/filters/client_channel/resolver.h',
+                      'src/core/ext/filters/client_channel/resolver_factory.h',
+                      'src/core/ext/filters/client_channel/resolver_registry.h',
+                      'src/core/ext/filters/client_channel/retry_throttle.h',
+                      'src/core/ext/filters/client_channel/subchannel.h',
+                      'src/core/ext/filters/client_channel/subchannel_index.h',
+                      'src/core/ext/filters/client_channel/uri_parser.h',
                       'src/core/ext/transport/chttp2/client/chttp2_connector.h',
-                      'src/core/ext/lb_policy/grpclb/grpclb.h',
-                      'src/core/ext/lb_policy/grpclb/grpclb_channel.h',
-                      'src/core/ext/lb_policy/grpclb/load_balancer_api.h',
-                      'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
+                      'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
+                      'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
+                      'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
+                      'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
                       'third_party/nanopb/pb.h',
                       'third_party/nanopb/pb_common.h',
                       'third_party/nanopb/pb_decode.h',
                       'third_party/nanopb/pb_encode.h',
-                      'src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h',
-                      'src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h',
-                      'src/core/ext/load_reporting/load_reporting.h',
-                      'src/core/ext/load_reporting/load_reporting_filter.h',
+                      'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
+                      'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
+                      'src/core/ext/filters/load_reporting/load_reporting.h',
+                      'src/core/ext/filters/load_reporting/load_reporting_filter.h',
                       'src/core/ext/census/aggregation.h',
                       'src/core/ext/census/base_resources.h',
                       'src/core/ext/census/census_interface.h',
@@ -457,6 +456,7 @@
                       'src/core/ext/census/trace_status.h',
                       'src/core/ext/census/trace_string.h',
                       'src/core/ext/census/tracing.h',
+                      'src/core/ext/filters/max_age/max_age_filter.h',
                       'src/core/lib/surface/init.c',
                       'src/core/lib/channel/channel_args.c',
                       'src/core/lib/channel/channel_stack.c',
@@ -469,7 +469,6 @@
                       'src/core/lib/channel/handshaker_registry.c',
                       'src/core/lib/channel/http_client_filter.c',
                       'src/core/lib/channel/http_server_filter.c',
-                      'src/core/lib/channel/max_age_filter.c',
                       'src/core/lib/channel/message_size_filter.c',
                       'src/core/lib/compression/compression.c',
                       'src/core/lib/compression/message_compress.c',
@@ -634,47 +633,47 @@
                       'src/core/tsi/transport_security.c',
                       'src/core/ext/transport/chttp2/server/chttp2_server.c',
                       'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
-                      'src/core/ext/client_channel/channel_connectivity.c',
-                      'src/core/ext/client_channel/client_channel.c',
-                      'src/core/ext/client_channel/client_channel_factory.c',
-                      'src/core/ext/client_channel/client_channel_plugin.c',
-                      'src/core/ext/client_channel/connector.c',
-                      'src/core/ext/client_channel/http_connect_handshaker.c',
-                      'src/core/ext/client_channel/http_proxy.c',
-                      'src/core/ext/client_channel/lb_policy.c',
-                      'src/core/ext/client_channel/lb_policy_factory.c',
-                      'src/core/ext/client_channel/lb_policy_registry.c',
-                      'src/core/ext/client_channel/parse_address.c',
-                      'src/core/ext/client_channel/proxy_mapper.c',
-                      'src/core/ext/client_channel/proxy_mapper_registry.c',
-                      'src/core/ext/client_channel/resolver.c',
-                      'src/core/ext/client_channel/resolver_factory.c',
-                      'src/core/ext/client_channel/resolver_registry.c',
-                      'src/core/ext/client_channel/retry_throttle.c',
-                      'src/core/ext/client_channel/subchannel.c',
-                      'src/core/ext/client_channel/subchannel_index.c',
-                      'src/core/ext/client_channel/uri_parser.c',
+                      'src/core/ext/filters/client_channel/channel_connectivity.c',
+                      'src/core/ext/filters/client_channel/client_channel.c',
+                      'src/core/ext/filters/client_channel/client_channel_factory.c',
+                      'src/core/ext/filters/client_channel/client_channel_plugin.c',
+                      'src/core/ext/filters/client_channel/connector.c',
+                      'src/core/ext/filters/client_channel/http_connect_handshaker.c',
+                      'src/core/ext/filters/client_channel/http_proxy.c',
+                      'src/core/ext/filters/client_channel/lb_policy.c',
+                      'src/core/ext/filters/client_channel/lb_policy_factory.c',
+                      'src/core/ext/filters/client_channel/lb_policy_registry.c',
+                      'src/core/ext/filters/client_channel/parse_address.c',
+                      'src/core/ext/filters/client_channel/proxy_mapper.c',
+                      'src/core/ext/filters/client_channel/proxy_mapper_registry.c',
+                      'src/core/ext/filters/client_channel/resolver.c',
+                      'src/core/ext/filters/client_channel/resolver_factory.c',
+                      'src/core/ext/filters/client_channel/resolver_registry.c',
+                      'src/core/ext/filters/client_channel/retry_throttle.c',
+                      'src/core/ext/filters/client_channel/subchannel.c',
+                      'src/core/ext/filters/client_channel/subchannel_index.c',
+                      'src/core/ext/filters/client_channel/uri_parser.c',
                       'src/core/ext/transport/chttp2/client/chttp2_connector.c',
                       'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
                       'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
                       'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
                       'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
-                      'src/core/ext/lb_policy/grpclb/grpclb.c',
-                      'src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c',
-                      'src/core/ext/lb_policy/grpclb/load_balancer_api.c',
-                      'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
+                      'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c',
+                      'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c',
+                      'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c',
+                      'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
                       'third_party/nanopb/pb_common.c',
                       'third_party/nanopb/pb_decode.c',
                       'third_party/nanopb/pb_encode.c',
-                      'src/core/ext/lb_policy/pick_first/pick_first.c',
-                      'src/core/ext/lb_policy/round_robin/round_robin.c',
-                      'src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c',
-                      'src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
-                      'src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c',
-                      'src/core/ext/resolver/dns/native/dns_resolver.c',
-                      'src/core/ext/resolver/sockaddr/sockaddr_resolver.c',
-                      'src/core/ext/load_reporting/load_reporting.c',
-                      'src/core/ext/load_reporting/load_reporting_filter.c',
+                      'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c',
+                      'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c',
+                      'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c',
+                      'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
+                      'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c',
+                      'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c',
+                      'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c',
+                      'src/core/ext/filters/load_reporting/load_reporting.c',
+                      'src/core/ext/filters/load_reporting/load_reporting_filter.c',
                       'src/core/ext/census/base_resources.c',
                       'src/core/ext/census/context.c',
                       'src/core/ext/census/gen/census.pb.c',
@@ -689,6 +688,7 @@
                       'src/core/ext/census/resource.c',
                       'src/core/ext/census/trace_context.c',
                       'src/core/ext/census/tracing.c',
+                      'src/core/ext/filters/max_age/max_age_filter.c',
                       'src/core/plugin_registry/grpc_plugin_registry.c'
 
     ss.private_header_files = 'src/core/lib/profiling/timers.h',
@@ -717,7 +717,6 @@
                               'src/core/lib/channel/handshaker_registry.h',
                               'src/core/lib/channel/http_client_filter.h',
                               'src/core/lib/channel/http_server_filter.h',
-                              'src/core/lib/channel/max_age_filter.h',
                               'src/core/lib/channel/message_size_filter.h',
                               'src/core/lib/compression/algorithm_metadata.h',
                               'src/core/lib/compression/message_compress.h',
@@ -860,37 +859,37 @@
                               'src/core/tsi/transport_security.h',
                               'src/core/tsi/transport_security_interface.h',
                               'src/core/ext/transport/chttp2/server/chttp2_server.h',
-                              'src/core/ext/client_channel/client_channel.h',
-                              'src/core/ext/client_channel/client_channel_factory.h',
-                              'src/core/ext/client_channel/connector.h',
-                              'src/core/ext/client_channel/http_connect_handshaker.h',
-                              'src/core/ext/client_channel/http_proxy.h',
-                              'src/core/ext/client_channel/lb_policy.h',
-                              'src/core/ext/client_channel/lb_policy_factory.h',
-                              'src/core/ext/client_channel/lb_policy_registry.h',
-                              'src/core/ext/client_channel/parse_address.h',
-                              'src/core/ext/client_channel/proxy_mapper.h',
-                              'src/core/ext/client_channel/proxy_mapper_registry.h',
-                              'src/core/ext/client_channel/resolver.h',
-                              'src/core/ext/client_channel/resolver_factory.h',
-                              'src/core/ext/client_channel/resolver_registry.h',
-                              'src/core/ext/client_channel/retry_throttle.h',
-                              'src/core/ext/client_channel/subchannel.h',
-                              'src/core/ext/client_channel/subchannel_index.h',
-                              'src/core/ext/client_channel/uri_parser.h',
+                              'src/core/ext/filters/client_channel/client_channel.h',
+                              'src/core/ext/filters/client_channel/client_channel_factory.h',
+                              'src/core/ext/filters/client_channel/connector.h',
+                              'src/core/ext/filters/client_channel/http_connect_handshaker.h',
+                              'src/core/ext/filters/client_channel/http_proxy.h',
+                              'src/core/ext/filters/client_channel/lb_policy.h',
+                              'src/core/ext/filters/client_channel/lb_policy_factory.h',
+                              'src/core/ext/filters/client_channel/lb_policy_registry.h',
+                              'src/core/ext/filters/client_channel/parse_address.h',
+                              'src/core/ext/filters/client_channel/proxy_mapper.h',
+                              'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
+                              'src/core/ext/filters/client_channel/resolver.h',
+                              'src/core/ext/filters/client_channel/resolver_factory.h',
+                              'src/core/ext/filters/client_channel/resolver_registry.h',
+                              'src/core/ext/filters/client_channel/retry_throttle.h',
+                              'src/core/ext/filters/client_channel/subchannel.h',
+                              'src/core/ext/filters/client_channel/subchannel_index.h',
+                              'src/core/ext/filters/client_channel/uri_parser.h',
                               'src/core/ext/transport/chttp2/client/chttp2_connector.h',
-                              'src/core/ext/lb_policy/grpclb/grpclb.h',
-                              'src/core/ext/lb_policy/grpclb/grpclb_channel.h',
-                              'src/core/ext/lb_policy/grpclb/load_balancer_api.h',
-                              'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
+                              'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
+                              'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
+                              'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
+                              'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
                               'third_party/nanopb/pb.h',
                               'third_party/nanopb/pb_common.h',
                               'third_party/nanopb/pb_decode.h',
                               'third_party/nanopb/pb_encode.h',
-                              'src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h',
-                              'src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h',
-                              'src/core/ext/load_reporting/load_reporting.h',
-                              'src/core/ext/load_reporting/load_reporting_filter.h',
+                              'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
+                              'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
+                              'src/core/ext/filters/load_reporting/load_reporting.h',
+                              'src/core/ext/filters/load_reporting/load_reporting_filter.h',
                               'src/core/ext/census/aggregation.h',
                               'src/core/ext/census/base_resources.h',
                               'src/core/ext/census/census_interface.h',
@@ -906,7 +905,8 @@
                               'src/core/ext/census/trace_propagation.h',
                               'src/core/ext/census/trace_status.h',
                               'src/core/ext/census/trace_string.h',
-                              'src/core/ext/census/tracing.h'
+                              'src/core/ext/census/tracing.h',
+                              'src/core/ext/filters/max_age/max_age_filter.h'
   end
 
   s.subspec 'Cronet-Interface' do |ss|
diff --git a/grpc.gemspec b/grpc.gemspec
index 42d4298..6a20468 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -24,7 +24,7 @@
   s.files += Dir.glob('include/grpc/**/*')
   s.test_files = Dir.glob('src/ruby/spec/**/*')
   s.bindir = 'src/ruby/bin'
-  s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
+  s.require_paths = %w( src/ruby/lib src/ruby/bin src/ruby/pb )
   s.platform      = Gem::Platform::RUBY
 
   s.add_dependency 'google-protobuf', '~> 3.1'
@@ -183,7 +183,6 @@
   s.files += %w( src/core/lib/channel/handshaker_registry.h )
   s.files += %w( src/core/lib/channel/http_client_filter.h )
   s.files += %w( src/core/lib/channel/http_server_filter.h )
-  s.files += %w( src/core/lib/channel/max_age_filter.h )
   s.files += %w( src/core/lib/channel/message_size_filter.h )
   s.files += %w( src/core/lib/compression/algorithm_metadata.h )
   s.files += %w( src/core/lib/compression/message_compress.h )
@@ -326,37 +325,37 @@
   s.files += %w( src/core/tsi/transport_security.h )
   s.files += %w( src/core/tsi/transport_security_interface.h )
   s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.h )
-  s.files += %w( src/core/ext/client_channel/client_channel.h )
-  s.files += %w( src/core/ext/client_channel/client_channel_factory.h )
-  s.files += %w( src/core/ext/client_channel/connector.h )
-  s.files += %w( src/core/ext/client_channel/http_connect_handshaker.h )
-  s.files += %w( src/core/ext/client_channel/http_proxy.h )
-  s.files += %w( src/core/ext/client_channel/lb_policy.h )
-  s.files += %w( src/core/ext/client_channel/lb_policy_factory.h )
-  s.files += %w( src/core/ext/client_channel/lb_policy_registry.h )
-  s.files += %w( src/core/ext/client_channel/parse_address.h )
-  s.files += %w( src/core/ext/client_channel/proxy_mapper.h )
-  s.files += %w( src/core/ext/client_channel/proxy_mapper_registry.h )
-  s.files += %w( src/core/ext/client_channel/resolver.h )
-  s.files += %w( src/core/ext/client_channel/resolver_factory.h )
-  s.files += %w( src/core/ext/client_channel/resolver_registry.h )
-  s.files += %w( src/core/ext/client_channel/retry_throttle.h )
-  s.files += %w( src/core/ext/client_channel/subchannel.h )
-  s.files += %w( src/core/ext/client_channel/subchannel_index.h )
-  s.files += %w( src/core/ext/client_channel/uri_parser.h )
+  s.files += %w( src/core/ext/filters/client_channel/client_channel.h )
+  s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.h )
+  s.files += %w( src/core/ext/filters/client_channel/connector.h )
+  s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.h )
+  s.files += %w( src/core/ext/filters/client_channel/http_proxy.h )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy.h )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.h )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.h )
+  s.files += %w( src/core/ext/filters/client_channel/parse_address.h )
+  s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.h )
+  s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.h )
+  s.files += %w( src/core/ext/filters/client_channel/resolver.h )
+  s.files += %w( src/core/ext/filters/client_channel/resolver_factory.h )
+  s.files += %w( src/core/ext/filters/client_channel/resolver_registry.h )
+  s.files += %w( src/core/ext/filters/client_channel/retry_throttle.h )
+  s.files += %w( src/core/ext/filters/client_channel/subchannel.h )
+  s.files += %w( src/core/ext/filters/client_channel/subchannel_index.h )
+  s.files += %w( src/core/ext/filters/client_channel/uri_parser.h )
   s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.h )
-  s.files += %w( src/core/ext/lb_policy/grpclb/grpclb.h )
-  s.files += %w( src/core/ext/lb_policy/grpclb/grpclb_channel.h )
-  s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.h )
-  s.files += %w( src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h )
   s.files += %w( third_party/nanopb/pb.h )
   s.files += %w( third_party/nanopb/pb_common.h )
   s.files += %w( third_party/nanopb/pb_decode.h )
   s.files += %w( third_party/nanopb/pb_encode.h )
-  s.files += %w( src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h )
-  s.files += %w( src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h )
-  s.files += %w( src/core/ext/load_reporting/load_reporting.h )
-  s.files += %w( src/core/ext/load_reporting/load_reporting_filter.h )
+  s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h )
+  s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h )
+  s.files += %w( src/core/ext/filters/load_reporting/load_reporting.h )
+  s.files += %w( src/core/ext/filters/load_reporting/load_reporting_filter.h )
   s.files += %w( src/core/ext/census/aggregation.h )
   s.files += %w( src/core/ext/census/base_resources.h )
   s.files += %w( src/core/ext/census/census_interface.h )
@@ -373,6 +372,7 @@
   s.files += %w( src/core/ext/census/trace_status.h )
   s.files += %w( src/core/ext/census/trace_string.h )
   s.files += %w( src/core/ext/census/tracing.h )
+  s.files += %w( src/core/ext/filters/max_age/max_age_filter.h )
   s.files += %w( src/core/lib/surface/init.c )
   s.files += %w( src/core/lib/channel/channel_args.c )
   s.files += %w( src/core/lib/channel/channel_stack.c )
@@ -385,7 +385,6 @@
   s.files += %w( src/core/lib/channel/handshaker_registry.c )
   s.files += %w( src/core/lib/channel/http_client_filter.c )
   s.files += %w( src/core/lib/channel/http_server_filter.c )
-  s.files += %w( src/core/lib/channel/max_age_filter.c )
   s.files += %w( src/core/lib/channel/message_size_filter.c )
   s.files += %w( src/core/lib/compression/compression.c )
   s.files += %w( src/core/lib/compression/message_compress.c )
@@ -550,47 +549,47 @@
   s.files += %w( src/core/tsi/transport_security.c )
   s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.c )
   s.files += %w( src/core/ext/transport/chttp2/client/secure/secure_channel_create.c )
-  s.files += %w( src/core/ext/client_channel/channel_connectivity.c )
-  s.files += %w( src/core/ext/client_channel/client_channel.c )
-  s.files += %w( src/core/ext/client_channel/client_channel_factory.c )
-  s.files += %w( src/core/ext/client_channel/client_channel_plugin.c )
-  s.files += %w( src/core/ext/client_channel/connector.c )
-  s.files += %w( src/core/ext/client_channel/http_connect_handshaker.c )
-  s.files += %w( src/core/ext/client_channel/http_proxy.c )
-  s.files += %w( src/core/ext/client_channel/lb_policy.c )
-  s.files += %w( src/core/ext/client_channel/lb_policy_factory.c )
-  s.files += %w( src/core/ext/client_channel/lb_policy_registry.c )
-  s.files += %w( src/core/ext/client_channel/parse_address.c )
-  s.files += %w( src/core/ext/client_channel/proxy_mapper.c )
-  s.files += %w( src/core/ext/client_channel/proxy_mapper_registry.c )
-  s.files += %w( src/core/ext/client_channel/resolver.c )
-  s.files += %w( src/core/ext/client_channel/resolver_factory.c )
-  s.files += %w( src/core/ext/client_channel/resolver_registry.c )
-  s.files += %w( src/core/ext/client_channel/retry_throttle.c )
-  s.files += %w( src/core/ext/client_channel/subchannel.c )
-  s.files += %w( src/core/ext/client_channel/subchannel_index.c )
-  s.files += %w( src/core/ext/client_channel/uri_parser.c )
+  s.files += %w( src/core/ext/filters/client_channel/channel_connectivity.c )
+  s.files += %w( src/core/ext/filters/client_channel/client_channel.c )
+  s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.c )
+  s.files += %w( src/core/ext/filters/client_channel/client_channel_plugin.c )
+  s.files += %w( src/core/ext/filters/client_channel/connector.c )
+  s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.c )
+  s.files += %w( src/core/ext/filters/client_channel/http_proxy.c )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy.c )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.c )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.c )
+  s.files += %w( src/core/ext/filters/client_channel/parse_address.c )
+  s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.c )
+  s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.c )
+  s.files += %w( src/core/ext/filters/client_channel/resolver.c )
+  s.files += %w( src/core/ext/filters/client_channel/resolver_factory.c )
+  s.files += %w( src/core/ext/filters/client_channel/resolver_registry.c )
+  s.files += %w( src/core/ext/filters/client_channel/retry_throttle.c )
+  s.files += %w( src/core/ext/filters/client_channel/subchannel.c )
+  s.files += %w( src/core/ext/filters/client_channel/subchannel_index.c )
+  s.files += %w( src/core/ext/filters/client_channel/uri_parser.c )
   s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.c )
   s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2.c )
   s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c )
   s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create.c )
   s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c )
-  s.files += %w( src/core/ext/lb_policy/grpclb/grpclb.c )
-  s.files += %w( src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c )
-  s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.c )
-  s.files += %w( src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c )
   s.files += %w( third_party/nanopb/pb_common.c )
   s.files += %w( third_party/nanopb/pb_decode.c )
   s.files += %w( third_party/nanopb/pb_encode.c )
-  s.files += %w( src/core/ext/lb_policy/pick_first/pick_first.c )
-  s.files += %w( src/core/ext/lb_policy/round_robin/round_robin.c )
-  s.files += %w( src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c )
-  s.files += %w( src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c )
-  s.files += %w( src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c )
-  s.files += %w( src/core/ext/resolver/dns/native/dns_resolver.c )
-  s.files += %w( src/core/ext/resolver/sockaddr/sockaddr_resolver.c )
-  s.files += %w( src/core/ext/load_reporting/load_reporting.c )
-  s.files += %w( src/core/ext/load_reporting/load_reporting_filter.c )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c )
+  s.files += %w( src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c )
+  s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c )
+  s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c )
+  s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c )
+  s.files += %w( src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c )
+  s.files += %w( src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c )
+  s.files += %w( src/core/ext/filters/load_reporting/load_reporting.c )
+  s.files += %w( src/core/ext/filters/load_reporting/load_reporting_filter.c )
   s.files += %w( src/core/ext/census/base_resources.c )
   s.files += %w( src/core/ext/census/context.c )
   s.files += %w( src/core/ext/census/gen/census.pb.c )
@@ -605,6 +604,7 @@
   s.files += %w( src/core/ext/census/resource.c )
   s.files += %w( src/core/ext/census/trace_context.c )
   s.files += %w( src/core/ext/census/tracing.c )
+  s.files += %w( src/core/ext/filters/max_age/max_age_filter.c )
   s.files += %w( src/core/plugin_registry/grpc_plugin_registry.c )
   s.files += %w( third_party/boringssl/crypto/aes/internal.h )
   s.files += %w( third_party/boringssl/crypto/asn1/asn1_locl.h )
diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h
index a3f2be6..be6857c 100644
--- a/include/grpc++/impl/codegen/call.h
+++ b/include/grpc++/impl/codegen/call.h
@@ -528,6 +528,7 @@
   void ClientRecvStatus(ClientContext* context, Status* status) {
     metadata_map_ = &context->trailing_metadata_;
     recv_status_ = status;
+    status_details_ = g_core_codegen_interface->grpc_empty_slice();
   }
 
  protected:
diff --git a/include/grpc++/impl/codegen/core_codegen.h b/include/grpc++/impl/codegen/core_codegen.h
index 754bf14..6bf9512 100644
--- a/include/grpc++/impl/codegen/core_codegen.h
+++ b/include/grpc++/impl/codegen/core_codegen.h
@@ -76,6 +76,7 @@
   grpc_byte_buffer* grpc_raw_byte_buffer_create(grpc_slice* slice,
                                                 size_t nslices) override;
 
+  grpc_slice grpc_empty_slice() override;
   grpc_slice grpc_slice_malloc(size_t length) override;
   void grpc_slice_unref(grpc_slice slice) override;
   grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split) override;
diff --git a/include/grpc++/impl/codegen/core_codegen_interface.h b/include/grpc++/impl/codegen/core_codegen_interface.h
index 45ea040..e111d59 100644
--- a/include/grpc++/impl/codegen/core_codegen_interface.h
+++ b/include/grpc++/impl/codegen/core_codegen_interface.h
@@ -94,6 +94,7 @@
   virtual grpc_byte_buffer* grpc_raw_byte_buffer_create(grpc_slice* slice,
                                                         size_t nslices) = 0;
 
+  virtual grpc_slice grpc_empty_slice() = 0;
   virtual grpc_slice grpc_slice_malloc(size_t length) = 0;
   virtual void grpc_slice_unref(grpc_slice slice) = 0;
   virtual grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split) = 0;
diff --git a/include/grpc/impl/codegen/atm_gcc_atomic.h b/include/grpc/impl/codegen/atm_gcc_atomic.h
index a486258..d52975c 100644
--- a/include/grpc/impl/codegen/atm_gcc_atomic.h
+++ b/include/grpc/impl/codegen/atm_gcc_atomic.h
@@ -39,6 +39,7 @@
 #include <grpc/impl/codegen/port_platform.h>
 
 typedef intptr_t gpr_atm;
+#define GPR_ATM_MAX INTPTR_MAX
 
 #ifdef GPR_LOW_LEVEL_COUNTERS
 extern gpr_atm gpr_counter_atm_cas;
diff --git a/include/grpc/impl/codegen/atm_gcc_sync.h b/include/grpc/impl/codegen/atm_gcc_sync.h
index 946545a..b537e48 100644
--- a/include/grpc/impl/codegen/atm_gcc_sync.h
+++ b/include/grpc/impl/codegen/atm_gcc_sync.h
@@ -39,6 +39,7 @@
 #include <grpc/impl/codegen/port_platform.h>
 
 typedef intptr_t gpr_atm;
+#define GPR_ATM_MAX INTPTR_MAX
 
 #define GPR_ATM_COMPILE_BARRIER_() __asm__ __volatile__("" : : : "memory")
 
diff --git a/include/grpc/impl/codegen/atm_windows.h b/include/grpc/impl/codegen/atm_windows.h
index 0ab70b9..b8f63da 100644
--- a/include/grpc/impl/codegen/atm_windows.h
+++ b/include/grpc/impl/codegen/atm_windows.h
@@ -38,6 +38,7 @@
 #include <grpc/impl/codegen/port_platform.h>
 
 typedef intptr_t gpr_atm;
+#define GPR_ATM_MAX INTPTR_MAX
 
 #define gpr_atm_full_barrier MemoryBarrier
 
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index aa4210b..fdedf0a 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -152,6 +152,9 @@
 #define GRPC_ARG_ENABLE_CENSUS "grpc.census"
 /** If non-zero, enable load reporting. */
 #define GRPC_ARG_ENABLE_LOAD_REPORTING "grpc.loadreporting"
+/** Request that optional features default to off (regardless of what they
+    usually default to) - to enable tight control over what gets enabled */
+#define GRPC_ARG_MINIMAL_STACK "grpc.minimal_stack"
 /** Maximum number of concurrent incoming streams to allow on a http2
     connection. Int valued. */
 #define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
@@ -202,15 +205,25 @@
      a data frame or header frame) */
 #define GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA \
   "grpc.http2.max_pings_without_data"
+/** How many misbehaving pings the server can bear before sending goaway and
+    closing the transport?
+    (0 indicates that the server can bear an infinite number of misbehaving
+     pings) */
+#define GRPC_ARG_HTTP2_MAX_PING_STRIKES "grpc.http2.max_ping_strikes"
+/** Minimum allowed time between two pings without sending any data frame. Int
+    valued, seconds */
+#define GRPC_ARG_HTTP2_MIN_PING_INTERVAL_WITHOUT_DATA_MS \
+  "grpc.http2.min_ping_interval_without_data_ms"
 /** How much data are we willing to queue up per stream if
     GRPC_WRITE_BUFFER_HINT is set? This is an upper bound */
 #define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size"
-/** After a duration of this time the client pings the server to see if the
-    transport is still alive. Int valued, seconds. */
-#define GRPC_ARG_CLIENT_KEEPALIVE_TIME_S "grpc.client_keepalive_time"
-/** After waiting for a duration of this time, if the client does not receive
-    the ping ack, it will close the transport. Int valued, seconds. */
-#define GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S "grpc.client_keepalive_timeout"
+/** After a duration of this time the client/server pings its peer to see if the
+    transport is still alive. Int valued, milliseconds. */
+#define GRPC_ARG_KEEPALIVE_TIME_MS "grpc.keepalive_time_ms"
+/** After waiting for a duration of this time, if the keepalive ping sender does
+    not receive the ping ack, it will close the transport. Int valued,
+    milliseconds. */
+#define GRPC_ARG_KEEPALIVE_TIMEOUT_MS "grpc.keepalive_timeout_ms"
 /** Is it permissible to send keepalive pings without any outstanding streams.
     Int valued, 0(false)/1(true). */
 #define GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS \
@@ -258,6 +271,14 @@
  * possible. */
 #define GRPC_ARG_USE_CRONET_PACKET_COALESCING \
   "grpc.use_cronet_packet_coalescing"
+/* Channel arg (integer) setting how large a slice to try and read from the wire
+each time recvmsg (or equivalent) is called */
+#define GRPC_ARG_TCP_READ_CHUNK_SIZE "grpc.experimental.tcp_read_chunk_size"
+#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
+#define GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE \
+  "grpc.experimental.tcp_min_read_chunk_size"
+#define GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE \
+  "grpc.experimental.tcp_max_read_chunk_size"
 /** \} */
 
 /** Result of a grpc call. If the caller satisfies the prerequisites of a
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index 0863946..d525083 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -375,8 +375,10 @@
 #ifndef GRPC_MUST_USE_RESULT
 #if defined(__GNUC__) && !defined(__MINGW32__)
 #define GRPC_MUST_USE_RESULT __attribute__((warn_unused_result))
+#define GPR_ALIGN_STRUCT(n) __attribute__((aligned(n)))
 #else
 #define GRPC_MUST_USE_RESULT
+#define GPR_ALIGN_STRUCT(n)
 #endif
 #endif
 
diff --git a/include/grpc/support/tls.h b/include/grpc/support/tls.h
index a45e1f0..5365449 100644
--- a/include/grpc/support/tls.h
+++ b/include/grpc/support/tls.h
@@ -58,7 +58,7 @@
      gpr_tls_set(&foo, new_value);
 
    Accessing a thread local:
-     current_value = gpr_tls_get(&foo, value);
+     current_value = gpr_tls_get(&foo);
 
    ALL functions here may be implemented as macros. */
 
diff --git a/package.json b/package.json
index 666e819..7f24232 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,7 @@
     "lodash": "^4.15.0",
     "nan": "^2.0.0",
     "node-pre-gyp": "^0.6.0",
-    "protobufjs": "^5.0.0",
+    "protobufjs": "^6.7.0",
     "cares": "^1.1.5"
   },
   "devDependencies": {
diff --git a/package.xml b/package.xml
index 382393c..6957ecc 100644
--- a/package.xml
+++ b/package.xml
@@ -192,7 +192,6 @@
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/http_client_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/http_server_filter.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/max_age_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/message_size_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/algorithm_metadata.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/message_compress.h" role="src" />
@@ -335,37 +334,37 @@
     <file baseinstalldir="/" name="src/core/tsi/transport_security.h" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/transport_security_interface.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel_factory.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/connector.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/http_connect_handshaker.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/http_proxy.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_factory.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_registry.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/parse_address.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/proxy_mapper.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/proxy_mapper_registry.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/resolver.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_factory.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_registry.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/retry_throttle.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/subchannel.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/subchannel_index.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/uri_parser.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_factory.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/connector.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_connect_handshaker.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_proxy.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_factory.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_registry.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/parse_address.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper_registry.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_factory.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/grpclb.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/grpclb_channel.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/load_balancer_api.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb.h" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_common.h" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_decode.h" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_encode.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/load_reporting/load_reporting.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/load_reporting/load_reporting_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/load_reporting/load_reporting.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/load_reporting/load_reporting_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/aggregation.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/base_resources.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/census_interface.h" role="src" />
@@ -382,6 +381,7 @@
     <file baseinstalldir="/" name="src/core/ext/census/trace_status.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/trace_string.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/tracing.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/max_age/max_age_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/init.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_args.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.c" role="src" />
@@ -394,7 +394,6 @@
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/http_client_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/http_server_filter.c" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/channel/max_age_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/message_size_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/compression.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/message_compress.c" role="src" />
@@ -559,47 +558,47 @@
     <file baseinstalldir="/" name="src/core/tsi/transport_security.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/secure/secure_channel_create.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/channel_connectivity.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel_factory.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel_plugin.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/connector.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/http_connect_handshaker.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/http_proxy.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_factory.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/lb_policy_registry.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/parse_address.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/proxy_mapper.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/proxy_mapper_registry.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/resolver.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_factory.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/resolver_registry.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/retry_throttle.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/subchannel.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/subchannel_index.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_channel/uri_parser.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/channel_connectivity.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_factory.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_plugin.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/connector.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_connect_handshaker.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/http_proxy.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_factory.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_registry.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/parse_address.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper_registry.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_factory.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/grpclb.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/load_balancer_api.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_common.c" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_decode.c" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_encode.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/lb_policy/pick_first/pick_first.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/lb_policy/round_robin/round_robin.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/resolver/dns/native/dns_resolver.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/resolver/sockaddr/sockaddr_resolver.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/load_reporting/load_reporting.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/load_reporting/load_reporting_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/load_reporting/load_reporting.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/load_reporting/load_reporting_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/base_resources.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/context.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/gen/census.pb.c" role="src" />
@@ -614,6 +613,7 @@
     <file baseinstalldir="/" name="src/core/ext/census/resource.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/trace_context.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/tracing.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/max_age/max_age_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/plugin_registry/grpc_plugin_registry.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/aes/internal.h" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/asn1_locl.h" role="src" />
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 2908b63..c01e830 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -40,6 +40,9 @@
 namespace grpc_cpp_generator {
 namespace {
 
+grpc::string message_header_ext() { return ".pb.h"; }
+grpc::string service_header_ext() { return ".grpc.pb.h"; }
+
 template <class T>
 grpc::string as_string(T x) {
   std::ostringstream out;
@@ -47,6 +50,14 @@
   return out.str();
 }
 
+inline bool ClientOnlyStreaming(const grpc_generator::Method *method) {
+  return method->ClientStreaming() && !method->ServerStreaming();
+}
+
+inline bool ServerOnlyStreaming(const grpc_generator::Method *method) {
+  return !method->ClientStreaming() && method->ServerStreaming();
+}
+
 grpc::string FilenameIdentifier(const grpc::string &filename) {
   grpc::string result;
   for (unsigned i = 0; i < filename.size(); i++) {
@@ -69,7 +80,8 @@
   return array + N;
 }
 
-void PrintIncludes(Printer *printer, const std::vector<grpc::string> &headers,
+void PrintIncludes(grpc_generator::Printer *printer,
+                   const std::vector<grpc::string> &headers,
                    const Parameters &params) {
   std::map<grpc::string, grpc::string> vars;
 
@@ -90,7 +102,8 @@
   }
 }
 
-grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) {
+grpc::string GetHeaderPrologue(grpc_generator::File *file,
+                               const Parameters & /*params*/) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -100,13 +113,13 @@
     vars["filename"] = file->filename();
     vars["filename_identifier"] = FilenameIdentifier(file->filename());
     vars["filename_base"] = file->filename_without_ext();
-    vars["message_header_ext"] = file->message_header_ext();
+    vars["message_header_ext"] = message_header_ext();
 
     printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
     printer->Print(vars,
                    "// If you make any local change, they will be lost.\n");
     printer->Print(vars, "// source: $filename$\n");
-    grpc::string leading_comments = file->GetLeadingComments();
+    grpc::string leading_comments = file->GetLeadingComments("//");
     if (!leading_comments.empty()) {
       printer->Print(vars, "// Original file comments:\n");
       printer->Print(leading_comments.c_str());
@@ -120,7 +133,8 @@
   return output;
 }
 
-grpc::string GetHeaderIncludes(File *file, const Parameters &params) {
+grpc::string GetHeaderIncludes(grpc_generator::File *file,
+                               const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -162,7 +176,7 @@
 }
 
 void PrintHeaderClientMethodInterfaces(
-    Printer *printer, const Method *method,
+    grpc_generator::Printer *printer, const grpc_generator::Method *method,
     std::map<grpc::string, grpc::string> *vars, bool is_public) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
@@ -187,7 +201,7 @@
                      "Async$Method$Raw(context, request, cq));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (method->ClientOnlyStreaming()) {
+    } else if (ClientOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>"
@@ -213,7 +227,7 @@
                      "Async$Method$Raw(context, response, cq, tag));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (method->ServerOnlyStreaming()) {
+    } else if (ServerOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>"
@@ -275,7 +289,7 @@
           "Async$Method$Raw(::grpc::ClientContext* context, "
           "const $Request$& request, "
           "::grpc::CompletionQueue* cq) = 0;\n");
-    } else if (method->ClientOnlyStreaming()) {
+    } else if (ClientOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "virtual ::grpc::ClientWriterInterface< $Request$>*"
@@ -286,7 +300,7 @@
                      " Async$Method$Raw(::grpc::ClientContext* context, "
                      "$Response$* response, "
                      "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
-    } else if (method->ServerOnlyStreaming()) {
+    } else if (ServerOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "virtual ::grpc::ClientReaderInterface< $Response$>* $Method$Raw("
@@ -311,7 +325,8 @@
   }
 }
 
-void PrintHeaderClientMethod(Printer *printer, const Method *method,
+void PrintHeaderClientMethod(grpc_generator::Printer *printer,
+                             const grpc_generator::Method *method,
                              std::map<grpc::string, grpc::string> *vars,
                              bool is_public) {
   (*vars)["Method"] = method->name();
@@ -336,7 +351,7 @@
                      "Async$Method$Raw(context, request, cq));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (method->ClientOnlyStreaming()) {
+    } else if (ClientOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientWriter< $Request$>>"
@@ -360,7 +375,7 @@
           "Async$Method$Raw(context, response, cq, tag));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (method->ServerOnlyStreaming()) {
+    } else if (ServerOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientReader< $Response$>>"
@@ -418,7 +433,7 @@
                      "Async$Method$Raw(::grpc::ClientContext* context, "
                      "const $Request$& request, "
                      "::grpc::CompletionQueue* cq) override;\n");
-    } else if (method->ClientOnlyStreaming()) {
+    } else if (ClientOnlyStreaming(method)) {
       printer->Print(*vars,
                      "::grpc::ClientWriter< $Request$>* $Method$Raw("
                      "::grpc::ClientContext* context, $Response$* response) "
@@ -427,7 +442,7 @@
                      "::grpc::ClientAsyncWriter< $Request$>* Async$Method$Raw("
                      "::grpc::ClientContext* context, $Response$* response, "
                      "::grpc::CompletionQueue* cq, void* tag) override;\n");
-    } else if (method->ServerOnlyStreaming()) {
+    } else if (ServerOnlyStreaming(method)) {
       printer->Print(*vars,
                      "::grpc::ClientReader< $Response$>* $Method$Raw("
                      "::grpc::ClientContext* context, const $Request$& request)"
@@ -449,30 +464,32 @@
   }
 }
 
-void PrintHeaderClientMethodData(Printer *printer, const Method *method,
+void PrintHeaderClientMethodData(grpc_generator::Printer *printer,
+                                 const grpc_generator::Method *method,
                                  std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   printer->Print(*vars, "const ::grpc::RpcMethod rpcmethod_$Method$_;\n");
 }
 
-void PrintHeaderServerMethodSync(Printer *printer, const Method *method,
+void PrintHeaderServerMethodSync(grpc_generator::Printer *printer,
+                                 const grpc_generator::Method *method,
                                  std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
   (*vars)["Response"] = method->output_type_name();
-  printer->Print(method->GetLeadingComments().c_str());
+  printer->Print(method->GetLeadingComments("//").c_str());
   if (method->NoStreaming()) {
     printer->Print(*vars,
                    "virtual ::grpc::Status $Method$("
                    "::grpc::ServerContext* context, const $Request$* request, "
                    "$Response$* response);\n");
-  } else if (method->ClientOnlyStreaming()) {
+  } else if (ClientOnlyStreaming(method)) {
     printer->Print(*vars,
                    "virtual ::grpc::Status $Method$("
                    "::grpc::ServerContext* context, "
                    "::grpc::ServerReader< $Request$>* reader, "
                    "$Response$* response);\n");
-  } else if (method->ServerOnlyStreaming()) {
+  } else if (ServerOnlyStreaming(method)) {
     printer->Print(*vars,
                    "virtual ::grpc::Status $Method$("
                    "::grpc::ServerContext* context, const $Request$* request, "
@@ -485,10 +502,11 @@
         "::grpc::ServerReaderWriter< $Response$, $Request$>* stream);"
         "\n");
   }
-  printer->Print(method->GetTrailingComments().c_str());
+  printer->Print(method->GetTrailingComments("//").c_str());
 }
 
-void PrintHeaderServerMethodAsync(Printer *printer, const Method *method,
+void PrintHeaderServerMethodAsync(grpc_generator::Printer *printer,
+                                  const grpc_generator::Method *method,
                                   std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
@@ -530,7 +548,7 @@
                    "  ::grpc::Service::RequestAsyncUnary($Idx$, context, "
                    "request, response, new_call_cq, notification_cq, tag);\n");
     printer->Print("}\n");
-  } else if (method->ClientOnlyStreaming()) {
+  } else if (ClientOnlyStreaming(method)) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -552,7 +570,7 @@
                    "  ::grpc::Service::RequestAsyncClientStreaming($Idx$, "
                    "context, reader, new_call_cq, notification_cq, tag);\n");
     printer->Print("}\n");
-  } else if (method->ServerOnlyStreaming()) {
+  } else if (ServerOnlyStreaming(method)) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -603,7 +621,7 @@
 }
 
 void PrintHeaderServerMethodStreamedUnary(
-    Printer *printer, const Method *method,
+    grpc_generator::Printer *printer, const grpc_generator::Method *method,
     std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
@@ -654,12 +672,12 @@
 }
 
 void PrintHeaderServerMethodSplitStreaming(
-    Printer *printer, const Method *method,
+    grpc_generator::Printer *printer, const grpc_generator::Method *method,
     std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
   (*vars)["Response"] = method->output_type_name();
-  if (method->ServerOnlyStreaming()) {
+  if (ServerOnlyStreaming(method)) {
     printer->Print(*vars, "template <class BaseClass>\n");
     printer->Print(*vars,
                    "class WithSplitStreamingMethod_$Method$ : "
@@ -706,7 +724,7 @@
 }
 
 void PrintHeaderServerMethodGeneric(
-    Printer *printer, const Method *method,
+    grpc_generator::Printer *printer, const grpc_generator::Method *method,
     std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
@@ -737,7 +755,7 @@
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
         "}\n");
-  } else if (method->ClientOnlyStreaming()) {
+  } else if (ClientOnlyStreaming(method)) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -748,7 +766,7 @@
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
         "}\n");
-  } else if (method->ServerOnlyStreaming()) {
+  } else if (ServerOnlyStreaming(method)) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
@@ -775,11 +793,12 @@
   printer->Print(*vars, "};\n");
 }
 
-void PrintHeaderService(Printer *printer, const Service *service,
+void PrintHeaderService(grpc_generator::Printer *printer,
+                        const grpc_generator::Service *service,
                         std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Service"] = service->name();
 
-  printer->Print(service->GetLeadingComments().c_str());
+  printer->Print(service->GetLeadingComments("//").c_str());
   printer->Print(*vars,
                  "class $Service$ final {\n"
                  " public:\n");
@@ -792,10 +811,10 @@
   printer->Indent();
   printer->Print("virtual ~StubInterface() {}\n");
   for (int i = 0; i < service->method_count(); ++i) {
-    printer->Print(service->method(i)->GetLeadingComments().c_str());
+    printer->Print(service->method(i)->GetLeadingComments("//").c_str());
     PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars,
                                       true);
-    printer->Print(service->method(i)->GetTrailingComments().c_str());
+    printer->Print(service->method(i)->GetTrailingComments("//").c_str());
   }
   printer->Outdent();
   printer->Print("private:\n");
@@ -903,13 +922,15 @@
   printer->Print("typedef ");
   for (int i = 0; i < service->method_count(); ++i) {
     (*vars)["method_name"] = service->method(i).get()->name();
-    if (service->method(i)->ServerOnlyStreaming()) {
+    auto method = service->method(i);
+    if (ServerOnlyStreaming(method.get())) {
       printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<");
     }
   }
   printer->Print("Service");
   for (int i = 0; i < service->method_count(); ++i) {
-    if (service->method(i)->ServerOnlyStreaming()) {
+    auto method = service->method(i);
+    if (ServerOnlyStreaming(method.get())) {
       printer->Print(" >");
     }
   }
@@ -919,7 +940,8 @@
   printer->Print("typedef ");
   for (int i = 0; i < service->method_count(); ++i) {
     (*vars)["method_name"] = service->method(i).get()->name();
-    if (service->method(i)->ServerOnlyStreaming()) {
+    auto method = service->method(i);
+    if (ServerOnlyStreaming(method.get())) {
       printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<");
     }
     if (service->method(i)->NoStreaming()) {
@@ -928,8 +950,9 @@
   }
   printer->Print("Service");
   for (int i = 0; i < service->method_count(); ++i) {
+    auto method = service->method(i);
     if (service->method(i)->NoStreaming() ||
-        service->method(i)->ServerOnlyStreaming()) {
+        ServerOnlyStreaming(method.get())) {
       printer->Print(" >");
     }
   }
@@ -937,10 +960,11 @@
 
   printer->Outdent();
   printer->Print("};\n");
-  printer->Print(service->GetTrailingComments().c_str());
+  printer->Print(service->GetTrailingComments("//").c_str());
 }
 
-grpc::string GetHeaderServices(File *file, const Parameters &params) {
+grpc::string GetHeaderServices(grpc_generator::File *file,
+                               const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -970,7 +994,8 @@
   return output;
 }
 
-grpc::string GetHeaderEpilogue(File *file, const Parameters & /*params*/) {
+grpc::string GetHeaderEpilogue(grpc_generator::File *file,
+                               const Parameters & /*params*/) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -993,12 +1018,13 @@
     printer->Print(vars, "\n");
     printer->Print(vars, "#endif  // GRPC_$filename_identifier$__INCLUDED\n");
 
-    printer->Print(file->GetTrailingComments().c_str());
+    printer->Print(file->GetTrailingComments("//").c_str());
   }
   return output;
 }
 
-grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) {
+grpc::string GetSourcePrologue(grpc_generator::File *file,
+                               const Parameters & /*params*/) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -1007,8 +1033,8 @@
 
     vars["filename"] = file->filename();
     vars["filename_base"] = file->filename_without_ext();
-    vars["message_header_ext"] = file->message_header_ext();
-    vars["service_header_ext"] = file->service_header_ext();
+    vars["message_header_ext"] = message_header_ext();
+    vars["service_header_ext"] = service_header_ext();
 
     printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
     printer->Print(vars,
@@ -1023,7 +1049,8 @@
   return output;
 }
 
-grpc::string GetSourceIncludes(File *file, const Parameters &params) {
+grpc::string GetSourceIncludes(grpc_generator::File *file,
+                               const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -1056,7 +1083,8 @@
   return output;
 }
 
-void PrintSourceClientMethod(Printer *printer, const Method *method,
+void PrintSourceClientMethod(grpc_generator::Printer *printer,
+                             const grpc_generator::Method *method,
                              std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
@@ -1084,7 +1112,7 @@
                    "rpcmethod_$Method$_, "
                    "context, request);\n"
                    "}\n\n");
-  } else if (method->ClientOnlyStreaming()) {
+  } else if (ClientOnlyStreaming(method)) {
     printer->Print(*vars,
                    "::grpc::ClientWriter< $Request$>* "
                    "$ns$$Service$::Stub::$Method$Raw("
@@ -1106,7 +1134,7 @@
                    "rpcmethod_$Method$_, "
                    "context, response, tag);\n"
                    "}\n\n");
-  } else if (method->ServerOnlyStreaming()) {
+  } else if (ServerOnlyStreaming(method)) {
     printer->Print(
         *vars,
         "::grpc::ClientReader< $Response$>* "
@@ -1156,7 +1184,8 @@
   }
 }
 
-void PrintSourceServerMethod(Printer *printer, const Method *method,
+void PrintSourceServerMethod(grpc_generator::Printer *printer,
+                             const grpc_generator::Method *method,
                              std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
@@ -1173,7 +1202,7 @@
         "  return ::grpc::Status("
         "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
     printer->Print("}\n\n");
-  } else if (method->ClientOnlyStreaming()) {
+  } else if (ClientOnlyStreaming(method)) {
     printer->Print(*vars,
                    "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
@@ -1186,7 +1215,7 @@
         "  return ::grpc::Status("
         "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
     printer->Print("}\n\n");
-  } else if (method->ServerOnlyStreaming()) {
+  } else if (ServerOnlyStreaming(method)) {
     printer->Print(*vars,
                    "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
@@ -1214,7 +1243,8 @@
   }
 }
 
-void PrintSourceService(Printer *printer, const Service *service,
+void PrintSourceService(grpc_generator::Printer *printer,
+                        const grpc_generator::Service *service,
                         std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Service"] = service->name();
 
@@ -1250,9 +1280,9 @@
       // NOTE: There is no reason to consider streamed-unary as a separate
       // category here since this part is setting up the client-side stub
       // and this appears as a NORMAL_RPC from the client-side.
-    } else if (method->ClientOnlyStreaming()) {
+    } else if (ClientOnlyStreaming(method.get())) {
       (*vars)["StreamingType"] = "CLIENT_STREAMING";
-    } else if (method->ServerOnlyStreaming()) {
+    } else if (ServerOnlyStreaming(method.get())) {
       (*vars)["StreamingType"] = "SERVER_STREAMING";
     } else {
       (*vars)["StreamingType"] = "BIDI_STREAMING";
@@ -1290,7 +1320,7 @@
           "$Request$, "
           "$Response$>(\n"
           "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
-    } else if (method->ClientOnlyStreaming()) {
+    } else if (ClientOnlyStreaming(method.get())) {
       printer->Print(
           *vars,
           "AddMethod(new ::grpc::RpcServiceMethod(\n"
@@ -1299,7 +1329,7 @@
           "    new ::grpc::ClientStreamingHandler< "
           "$ns$$Service$::Service, $Request$, $Response$>(\n"
           "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
-    } else if (method->ServerOnlyStreaming()) {
+    } else if (ServerOnlyStreaming(method.get())) {
       printer->Print(
           *vars,
           "AddMethod(new ::grpc::RpcServiceMethod(\n"
@@ -1330,7 +1360,8 @@
   }
 }
 
-grpc::string GetSourceServices(File *file, const Parameters &params) {
+grpc::string GetSourceServices(grpc_generator::File *file,
+                               const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -1358,7 +1389,8 @@
   return output;
 }
 
-grpc::string GetSourceEpilogue(File *file, const Parameters & /*params*/) {
+grpc::string GetSourceEpilogue(grpc_generator::File *file,
+                               const Parameters & /*params*/) {
   grpc::string temp;
 
   if (!file->package().empty()) {
diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h
index d0343e9..69fd8a9 100644
--- a/src/compiler/cpp_generator.h
+++ b/src/compiler/cpp_generator.h
@@ -42,6 +42,7 @@
 #include <vector>
 
 #include "src/compiler/config.h"
+#include "src/compiler/schema_interface.h"
 
 #ifndef GRPC_CUSTOM_STRING
 #include <string>
@@ -66,91 +67,37 @@
   grpc::string grpc_search_path;
 };
 
-// A common interface for objects having comments in the source.
-// Return formatted comments to be inserted in generated code.
-struct CommentHolder {
-  virtual ~CommentHolder() {}
-  virtual grpc::string GetLeadingComments() const = 0;
-  virtual grpc::string GetTrailingComments() const = 0;
-};
-
-// An abstract interface representing a method.
-struct Method : public CommentHolder {
-  virtual ~Method() {}
-
-  virtual grpc::string name() const = 0;
-
-  virtual grpc::string input_type_name() const = 0;
-  virtual grpc::string output_type_name() const = 0;
-
-  virtual bool NoStreaming() const = 0;
-  virtual bool ClientOnlyStreaming() const = 0;
-  virtual bool ServerOnlyStreaming() const = 0;
-  virtual bool BidiStreaming() const = 0;
-};
-
-// An abstract interface representing a service.
-struct Service : public CommentHolder {
-  virtual ~Service() {}
-
-  virtual grpc::string name() const = 0;
-
-  virtual int method_count() const = 0;
-  virtual std::unique_ptr<const Method> method(int i) const = 0;
-};
-
-struct Printer {
-  virtual ~Printer() {}
-
-  virtual void Print(const std::map<grpc::string, grpc::string> &vars,
-                     const char *template_string) = 0;
-  virtual void Print(const char *string) = 0;
-  virtual void Indent() = 0;
-  virtual void Outdent() = 0;
-};
-
-// An interface that allows the source generated to be output using various
-// libraries/idls/serializers.
-struct File : public CommentHolder {
-  virtual ~File() {}
-
-  virtual grpc::string filename() const = 0;
-  virtual grpc::string filename_without_ext() const = 0;
-  virtual grpc::string message_header_ext() const = 0;
-  virtual grpc::string service_header_ext() const = 0;
-  virtual grpc::string package() const = 0;
-  virtual std::vector<grpc::string> package_parts() const = 0;
-  virtual grpc::string additional_headers() const = 0;
-
-  virtual int service_count() const = 0;
-  virtual std::unique_ptr<const Service> service(int i) const = 0;
-
-  virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0;
-};
-
 // Return the prologue of the generated header file.
-grpc::string GetHeaderPrologue(File *file, const Parameters &params);
+grpc::string GetHeaderPrologue(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the includes needed for generated header file.
-grpc::string GetHeaderIncludes(File *file, const Parameters &params);
+grpc::string GetHeaderIncludes(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the includes needed for generated source file.
-grpc::string GetSourceIncludes(File *file, const Parameters &params);
+grpc::string GetSourceIncludes(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the epilogue of the generated header file.
-grpc::string GetHeaderEpilogue(File *file, const Parameters &params);
+grpc::string GetHeaderEpilogue(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the prologue of the generated source file.
-grpc::string GetSourcePrologue(File *file, const Parameters &params);
+grpc::string GetSourcePrologue(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the services for generated header file.
-grpc::string GetHeaderServices(File *file, const Parameters &params);
+grpc::string GetHeaderServices(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the services for generated source file.
-grpc::string GetSourceServices(File *file, const Parameters &params);
+grpc::string GetSourceServices(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the epilogue of the generated source file.
-grpc::string GetSourceEpilogue(File *file, const Parameters &params);
+grpc::string GetSourceEpilogue(grpc_generator::File *file,
+                               const Parameters &params);
 
 }  // namespace grpc_cpp_generator
 
diff --git a/src/compiler/cpp_generator_helpers.h b/src/compiler/cpp_generator_helpers.h
index 87e278f..83932a0 100644
--- a/src/compiler/cpp_generator_helpers.h
+++ b/src/compiler/cpp_generator_helpers.h
@@ -35,6 +35,7 @@
 #define GRPC_INTERNAL_COMPILER_CPP_GENERATOR_HELPERS_H
 
 #include <map>
+
 #include "src/compiler/config.h"
 #include "src/compiler/generator_helpers.h"
 
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index 38f8f73..4ee05ee 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -40,139 +40,8 @@
 #include "src/compiler/config.h"
 
 #include "src/compiler/cpp_generator.h"
-#include "src/compiler/cpp_generator_helpers.h"
 #include "src/compiler/generator_helpers.h"
-
-using grpc_cpp_generator::GetCppComments;
-
-class ProtoBufMethod : public grpc_cpp_generator::Method {
- public:
-  ProtoBufMethod(const grpc::protobuf::MethodDescriptor *method)
-      : method_(method) {}
-
-  grpc::string name() const { return method_->name(); }
-
-  grpc::string input_type_name() const {
-    return grpc_cpp_generator::ClassName(method_->input_type(), true);
-  }
-  grpc::string output_type_name() const {
-    return grpc_cpp_generator::ClassName(method_->output_type(), true);
-  }
-
-  bool NoStreaming() const {
-    return !method_->client_streaming() && !method_->server_streaming();
-  }
-
-  bool ClientOnlyStreaming() const {
-    return method_->client_streaming() && !method_->server_streaming();
-  }
-
-  bool ServerOnlyStreaming() const {
-    return !method_->client_streaming() && method_->server_streaming();
-  }
-
-  bool BidiStreaming() const {
-    return method_->client_streaming() && method_->server_streaming();
-  }
-
-  grpc::string GetLeadingComments() const {
-    return GetCppComments(method_, true);
-  }
-
-  grpc::string GetTrailingComments() const {
-    return GetCppComments(method_, false);
-  }
-
- private:
-  const grpc::protobuf::MethodDescriptor *method_;
-};
-
-class ProtoBufService : public grpc_cpp_generator::Service {
- public:
-  ProtoBufService(const grpc::protobuf::ServiceDescriptor *service)
-      : service_(service) {}
-
-  grpc::string name() const { return service_->name(); }
-
-  int method_count() const { return service_->method_count(); };
-  std::unique_ptr<const grpc_cpp_generator::Method> method(int i) const {
-    return std::unique_ptr<const grpc_cpp_generator::Method>(
-        new ProtoBufMethod(service_->method(i)));
-  };
-
-  grpc::string GetLeadingComments() const {
-    return GetCppComments(service_, true);
-  }
-
-  grpc::string GetTrailingComments() const {
-    return GetCppComments(service_, false);
-  }
-
- private:
-  const grpc::protobuf::ServiceDescriptor *service_;
-};
-
-class ProtoBufPrinter : public grpc_cpp_generator::Printer {
- public:
-  ProtoBufPrinter(grpc::string *str)
-      : output_stream_(str), printer_(&output_stream_, '$') {}
-
-  void Print(const std::map<grpc::string, grpc::string> &vars,
-             const char *string_template) {
-    printer_.Print(vars, string_template);
-  }
-
-  void Print(const char *string) { printer_.Print(string); }
-  void Indent() { printer_.Indent(); }
-  void Outdent() { printer_.Outdent(); }
-
- private:
-  grpc::protobuf::io::StringOutputStream output_stream_;
-  grpc::protobuf::io::Printer printer_;
-};
-
-class ProtoBufFile : public grpc_cpp_generator::File {
- public:
-  ProtoBufFile(const grpc::protobuf::FileDescriptor *file) : file_(file) {}
-
-  grpc::string filename() const { return file_->name(); }
-  grpc::string filename_without_ext() const {
-    return grpc_generator::StripProto(filename());
-  }
-
-  grpc::string message_header_ext() const { return ".pb.h"; }
-  grpc::string service_header_ext() const { return ".grpc.pb.h"; }
-
-  grpc::string package() const { return file_->package(); }
-  std::vector<grpc::string> package_parts() const {
-    return grpc_generator::tokenize(package(), ".");
-  }
-
-  grpc::string additional_headers() const { return ""; }
-
-  int service_count() const { return file_->service_count(); };
-  std::unique_ptr<const grpc_cpp_generator::Service> service(int i) const {
-    return std::unique_ptr<const grpc_cpp_generator::Service>(
-        new ProtoBufService(file_->service(i)));
-  }
-
-  std::unique_ptr<grpc_cpp_generator::Printer> CreatePrinter(
-      grpc::string *str) const {
-    return std::unique_ptr<grpc_cpp_generator::Printer>(
-        new ProtoBufPrinter(str));
-  }
-
-  grpc::string GetLeadingComments() const {
-    return GetCppComments(file_, true);
-  }
-
-  grpc::string GetTrailingComments() const {
-    return GetCppComments(file_, false);
-  }
-
- private:
-  const grpc::protobuf::FileDescriptor *file_;
-};
+#include "src/compiler/protobuf_plugin.h"
 
 class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
  public:
diff --git a/src/compiler/protobuf_plugin.h b/src/compiler/protobuf_plugin.h
new file mode 100644
index 0000000..cb01bd3
--- /dev/null
+++ b/src/compiler/protobuf_plugin.h
@@ -0,0 +1,210 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_PROTOBUF_PLUGIN_H
+#define GRPC_INTERNAL_COMPILER_PROTOBUF_PLUGIN_H
+
+#include "src/compiler/config.h"
+#include "src/compiler/cpp_generator_helpers.h"
+#include "src/compiler/python_generator_helpers.h"
+#include "src/compiler/python_private_generator.h"
+#include "src/compiler/schema_interface.h"
+
+#include <vector>
+
+// Get leading or trailing comments in a string.
+template <typename DescriptorType>
+inline grpc::string GetCommentsHelper(const DescriptorType *desc, bool leading,
+                                      const grpc::string &prefix) {
+  return grpc_generator::GetPrefixedComments(desc, leading, prefix);
+}
+
+class ProtoBufMethod : public grpc_generator::Method {
+ public:
+  ProtoBufMethod(const grpc::protobuf::MethodDescriptor *method)
+      : method_(method) {}
+
+  grpc::string name() const { return method_->name(); }
+
+  grpc::string input_type_name() const {
+    return grpc_cpp_generator::ClassName(method_->input_type(), true);
+  }
+  grpc::string output_type_name() const {
+    return grpc_cpp_generator::ClassName(method_->output_type(), true);
+  }
+
+  grpc::string get_input_type_name() const {
+    return method_->input_type()->file()->name();
+  }
+  grpc::string get_output_type_name() const {
+    return method_->output_type()->file()->name();
+  }
+
+  bool get_module_and_message_path_input(grpc::string *str,
+                                         grpc::string generator_file_name,
+                                         bool generate_in_pb2_grpc,
+                                         grpc::string import_prefix) const {
+    return grpc_python_generator::GetModuleAndMessagePath(
+        method_->input_type(), str, generator_file_name, generate_in_pb2_grpc,
+        import_prefix);
+  }
+
+  bool get_module_and_message_path_output(grpc::string *str,
+                                          grpc::string generator_file_name,
+                                          bool generate_in_pb2_grpc,
+                                          grpc::string import_prefix) const {
+    return grpc_python_generator::GetModuleAndMessagePath(
+        method_->output_type(), str, generator_file_name, generate_in_pb2_grpc,
+        import_prefix);
+  }
+
+  bool NoStreaming() const {
+    return !method_->client_streaming() && !method_->server_streaming();
+  }
+
+  bool ClientStreaming() const { return method_->client_streaming(); }
+
+  bool ServerStreaming() const { return method_->server_streaming(); }
+
+  bool BidiStreaming() const {
+    return method_->client_streaming() && method_->server_streaming();
+  }
+
+  grpc::string GetLeadingComments(const grpc::string prefix) const {
+    return GetCommentsHelper(method_, true, prefix);
+  }
+
+  grpc::string GetTrailingComments(const grpc::string prefix) const {
+    return GetCommentsHelper(method_, false, prefix);
+  }
+
+  vector<grpc::string> GetAllComments() const {
+    return grpc_python_generator::get_all_comments(method_);
+  }
+
+ private:
+  const grpc::protobuf::MethodDescriptor *method_;
+};
+
+class ProtoBufService : public grpc_generator::Service {
+ public:
+  ProtoBufService(const grpc::protobuf::ServiceDescriptor *service)
+      : service_(service) {}
+
+  grpc::string name() const { return service_->name(); }
+
+  int method_count() const { return service_->method_count(); };
+  std::unique_ptr<const grpc_generator::Method> method(int i) const {
+    return std::unique_ptr<const grpc_generator::Method>(
+        new ProtoBufMethod(service_->method(i)));
+  };
+
+  grpc::string GetLeadingComments(const grpc::string prefix) const {
+    return GetCommentsHelper(service_, true, prefix);
+  }
+
+  grpc::string GetTrailingComments(const grpc::string prefix) const {
+    return GetCommentsHelper(service_, false, prefix);
+  }
+
+  vector<grpc::string> GetAllComments() const {
+    return grpc_python_generator::get_all_comments(service_);
+  }
+
+ private:
+  const grpc::protobuf::ServiceDescriptor *service_;
+};
+
+class ProtoBufPrinter : public grpc_generator::Printer {
+ public:
+  ProtoBufPrinter(grpc::string *str)
+      : output_stream_(str), printer_(&output_stream_, '$') {}
+
+  void Print(const std::map<grpc::string, grpc::string> &vars,
+             const char *string_template) {
+    printer_.Print(vars, string_template);
+  }
+
+  void Print(const char *string) { printer_.Print(string); }
+  void Indent() { printer_.Indent(); }
+  void Outdent() { printer_.Outdent(); }
+
+ private:
+  grpc::protobuf::io::StringOutputStream output_stream_;
+  grpc::protobuf::io::Printer printer_;
+};
+
+class ProtoBufFile : public grpc_generator::File {
+ public:
+  ProtoBufFile(const grpc::protobuf::FileDescriptor *file) : file_(file) {}
+
+  grpc::string filename() const { return file_->name(); }
+  grpc::string filename_without_ext() const {
+    return grpc_generator::StripProto(filename());
+  }
+
+  grpc::string package() const { return file_->package(); }
+  std::vector<grpc::string> package_parts() const {
+    return grpc_generator::tokenize(package(), ".");
+  }
+
+  grpc::string additional_headers() const { return ""; }
+
+  int service_count() const { return file_->service_count(); };
+  std::unique_ptr<const grpc_generator::Service> service(int i) const {
+    return std::unique_ptr<const grpc_generator::Service>(
+        new ProtoBufService(file_->service(i)));
+  }
+
+  std::unique_ptr<grpc_generator::Printer> CreatePrinter(
+      grpc::string *str) const {
+    return std::unique_ptr<grpc_generator::Printer>(new ProtoBufPrinter(str));
+  }
+
+  grpc::string GetLeadingComments(const grpc::string prefix) const {
+    return GetCommentsHelper(file_, true, prefix);
+  }
+
+  grpc::string GetTrailingComments(const grpc::string prefix) const {
+    return GetCommentsHelper(file_, false, prefix);
+  }
+
+  vector<grpc::string> GetAllComments() const {
+    return grpc_python_generator::get_all_comments(file_);
+  }
+
+ private:
+  const grpc::protobuf::FileDescriptor *file_;
+};
+
+#endif  // GRPC_INTERNAL_COMPILER_PROTOBUF_PLUGIN_H
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index 49d90fd..2649c16 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -47,20 +47,15 @@
 
 #include "src/compiler/config.h"
 #include "src/compiler/generator_helpers.h"
+#include "src/compiler/protobuf_plugin.h"
 #include "src/compiler/python_generator.h"
+#include "src/compiler/python_generator_helpers.h"
+#include "src/compiler/python_private_generator.h"
 
-using grpc_generator::StringReplace;
-using grpc_generator::StripProto;
-using grpc::protobuf::Descriptor;
 using grpc::protobuf::FileDescriptor;
-using grpc::protobuf::MethodDescriptor;
-using grpc::protobuf::ServiceDescriptor;
 using grpc::protobuf::compiler::GeneratorContext;
 using grpc::protobuf::io::CodedOutputStream;
-using grpc::protobuf::io::Printer;
-using grpc::protobuf::io::StringOutputStream;
 using grpc::protobuf::io::ZeroCopyOutputStream;
-using std::initializer_list;
 using std::make_pair;
 using std::map;
 using std::pair;
@@ -71,9 +66,10 @@
 
 namespace grpc_python_generator {
 
+grpc::string generator_file_name;
+
 namespace {
 
-typedef vector<const Descriptor*> DescriptorVector;
 typedef map<grpc::string, grpc::string> StringMap;
 typedef vector<grpc::string> StringVector;
 typedef tuple<grpc::string, grpc::string> StringPair;
@@ -88,133 +84,22 @@
 // }
 class IndentScope {
  public:
-  explicit IndentScope(Printer* printer) : printer_(printer) {
+  explicit IndentScope(grpc_generator::Printer* printer) : printer_(printer) {
     printer_->Indent();
   }
 
   ~IndentScope() { printer_->Outdent(); }
 
  private:
-  Printer* printer_;
-};
-
-// TODO(https://github.com/google/protobuf/issues/888):
-// Export `ModuleName` from protobuf's
-// `src/google/protobuf/compiler/python/python_generator.cc` file.
-grpc::string ModuleName(const grpc::string& filename,
-                        const grpc::string& import_prefix) {
-  grpc::string basename = StripProto(filename);
-  basename = StringReplace(basename, "-", "_");
-  basename = StringReplace(basename, "/", ".");
-  return import_prefix + basename + "_pb2";
-}
-
-// TODO(https://github.com/google/protobuf/issues/888):
-// Export `ModuleAlias` from protobuf's
-// `src/google/protobuf/compiler/python/python_generator.cc` file.
-grpc::string ModuleAlias(const grpc::string& filename,
-                         const grpc::string& import_prefix) {
-  grpc::string module_name = ModuleName(filename, import_prefix);
-  // We can't have dots in the module name, so we replace each with _dot_.
-  // But that could lead to a collision between a.b and a_dot_b, so we also
-  // duplicate each underscore.
-  module_name = StringReplace(module_name, "_", "__");
-  module_name = StringReplace(module_name, ".", "_dot_");
-  return module_name;
-}
-
-// Tucks all generator state in an anonymous namespace away from
-// PythonGrpcGenerator and the header file, mostly to encourage future changes
-// to not require updates to the grpcio-tools C++ code part. Assumes that it is
-// only ever used from a single thread.
-struct PrivateGenerator {
-  const GeneratorConfiguration& config;
-  const FileDescriptor* file;
-
-  bool generate_in_pb2_grpc;
-
-  Printer* out;
-
-  PrivateGenerator(const GeneratorConfiguration& config,
-                   const FileDescriptor* file);
-
-  std::pair<bool, grpc::string> GetGrpcServices();
-
- private:
-  bool PrintPreamble();
-  bool PrintBetaPreamble();
-  bool PrintGAServices();
-  bool PrintBetaServices();
-
-  bool PrintAddServicerToServer(
-      const grpc::string& package_qualified_service_name,
-      const ServiceDescriptor* service);
-  bool PrintServicer(const ServiceDescriptor* service);
-  bool PrintStub(const grpc::string& package_qualified_service_name,
-                 const ServiceDescriptor* service);
-
-  bool PrintBetaServicer(const ServiceDescriptor* service);
-  bool PrintBetaServerFactory(
-      const grpc::string& package_qualified_service_name,
-      const ServiceDescriptor* service);
-  bool PrintBetaStub(const ServiceDescriptor* service);
-  bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name,
-                            const ServiceDescriptor* service);
-
-  // Get all comments (leading, leading_detached, trailing) and print them as a
-  // docstring. Any leading space of a line will be removed, but the line
-  // wrapping will not be changed.
-  template <typename DescriptorType>
-  void PrintAllComments(const DescriptorType* descriptor);
-
-  bool GetModuleAndMessagePath(const Descriptor* type, grpc::string* out);
+  grpc_generator::Printer* printer_;
 };
 
 PrivateGenerator::PrivateGenerator(const GeneratorConfiguration& config,
-                                   const FileDescriptor* file)
+                                   const grpc_generator::File* file)
     : config(config), file(file) {}
 
-bool PrivateGenerator::GetModuleAndMessagePath(const Descriptor* type,
-                                               grpc::string* out) {
-  const Descriptor* path_elem_type = type;
-  DescriptorVector message_path;
-  do {
-    message_path.push_back(path_elem_type);
-    path_elem_type = path_elem_type->containing_type();
-  } while (path_elem_type);  // implicit nullptr comparison; don't be explicit
-  grpc::string file_name = type->file()->name();
-  static const int proto_suffix_length = strlen(".proto");
-  if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) &&
-        file_name.find_last_of(".proto") == file_name.size() - 1)) {
-    return false;
-  }
-  grpc::string generator_file_name = file->name();
-  grpc::string module;
-  if (generator_file_name != file_name || generate_in_pb2_grpc) {
-    module = ModuleAlias(file_name, config.import_prefix) + ".";
-  } else {
-    module = "";
-  }
-  grpc::string message_type;
-  for (DescriptorVector::reverse_iterator path_iter = message_path.rbegin();
-       path_iter != message_path.rend(); ++path_iter) {
-    message_type += (*path_iter)->name() + ".";
-  }
-  // no pop_back prior to C++11
-  message_type.resize(message_type.size() - 1);
-  *out = module + message_type;
-  return true;
-}
-
-template <typename DescriptorType>
-void PrivateGenerator::PrintAllComments(const DescriptorType* descriptor) {
-  StringVector comments;
-  grpc_generator::GetComment(
-      descriptor, grpc_generator::COMMENTTYPE_LEADING_DETACHED, &comments);
-  grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_LEADING,
-                             &comments);
-  grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_TRAILING,
-                             &comments);
+void PrivateGenerator::PrintAllComments(StringVector comments,
+                                        grpc_generator::Printer* out) {
   if (comments.empty()) {
     return;
   }
@@ -230,10 +115,12 @@
   out->Print("\"\"\"\n");
 }
 
-bool PrivateGenerator::PrintBetaServicer(const ServiceDescriptor* service) {
+bool PrivateGenerator::PrintBetaServicer(const grpc_generator::Service* service,
+                                         grpc_generator::Printer* out) {
+  StringMap service_dict;
+  service_dict["Service"] = service->name();
   out->Print("\n\n");
-  out->Print("class Beta$Service$Servicer(object):\n", "Service",
-             service->name());
+  out->Print(service_dict, "class Beta$Service$Servicer(object):\n");
   {
     IndentScope raii_class_indent(out);
     out->Print(
@@ -243,16 +130,20 @@
         "generated\n"
         "only to ease transition from grpcio<0.15.0 to "
         "grpcio>=0.15.0.\"\"\"\n");
-    PrintAllComments(service);
+    StringVector service_comments = service->GetAllComments();
+    PrintAllComments(service_comments, out);
     for (int i = 0; i < service->method_count(); ++i) {
-      const MethodDescriptor* method = service->method(i);
+      auto method = service->method(i);
       grpc::string arg_name =
-          method->client_streaming() ? "request_iterator" : "request";
-      out->Print("def $Method$(self, $ArgName$, context):\n", "Method",
-                 method->name(), "ArgName", arg_name);
+          method->ClientStreaming() ? "request_iterator" : "request";
+      StringMap method_dict;
+      method_dict["Method"] = method->name();
+      method_dict["ArgName"] = arg_name;
+      out->Print(method_dict, "def $Method$(self, $ArgName$, context):\n");
       {
         IndentScope raii_method_indent(out);
-        PrintAllComments(method);
+        StringVector method_comments = method->GetAllComments();
+        PrintAllComments(method_comments, out);
         out->Print("context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)\n");
       }
     }
@@ -260,9 +151,12 @@
   return true;
 }
 
-bool PrivateGenerator::PrintBetaStub(const ServiceDescriptor* service) {
+bool PrivateGenerator::PrintBetaStub(const grpc_generator::Service* service,
+                                     grpc_generator::Printer* out) {
+  StringMap service_dict;
+  service_dict["Service"] = service->name();
   out->Print("\n\n");
-  out->Print("class Beta$Service$Stub(object):\n", "Service", service->name());
+  out->Print(service_dict, "class Beta$Service$Stub(object):\n");
   {
     IndentScope raii_class_indent(out);
     out->Print(
@@ -272,11 +166,12 @@
         "generated\n"
         "only to ease transition from grpcio<0.15.0 to "
         "grpcio>=0.15.0.\"\"\"\n");
-    PrintAllComments(service);
+    StringVector service_comments = service->GetAllComments();
+    PrintAllComments(service_comments, out);
     for (int i = 0; i < service->method_count(); ++i) {
-      const MethodDescriptor* method = service->method(i);
+      auto method = service->method(i);
       grpc::string arg_name =
-          method->client_streaming() ? "request_iterator" : "request";
+          method->ClientStreaming() ? "request_iterator" : "request";
       StringMap method_dict;
       method_dict["Method"] = method->name();
       method_dict["ArgName"] = arg_name;
@@ -285,10 +180,11 @@
                  "with_call=False, protocol_options=None):\n");
       {
         IndentScope raii_method_indent(out);
-        PrintAllComments(method);
+        StringVector method_comments = method->GetAllComments();
+        PrintAllComments(method_comments, out);
         out->Print("raise NotImplementedError()\n");
       }
-      if (!method->server_streaming()) {
+      if (!method->ServerStreaming()) {
         out->Print(method_dict, "$Method$.future = None\n");
       }
     }
@@ -298,12 +194,13 @@
 
 bool PrivateGenerator::PrintBetaServerFactory(
     const grpc::string& package_qualified_service_name,
-    const ServiceDescriptor* service) {
+    const grpc_generator::Service* service, grpc_generator::Printer* out) {
+  StringMap service_dict;
+  service_dict["Service"] = service->name();
   out->Print("\n\n");
-  out->Print(
-      "def beta_create_$Service$_server(servicer, pool=None, "
-      "pool_size=None, default_timeout=None, maximum_timeout=None):\n",
-      "Service", service->name());
+  out->Print(service_dict,
+             "def beta_create_$Service$_server(servicer, pool=None, "
+             "pool_size=None, default_timeout=None, maximum_timeout=None):\n");
   {
     IndentScope raii_create_server_indent(out);
     out->Print(
@@ -316,19 +213,21 @@
     StringMap input_message_modules_and_classes;
     StringMap output_message_modules_and_classes;
     for (int i = 0; i < service->method_count(); ++i) {
-      const MethodDescriptor* method = service->method(i);
+      auto method = service->method(i);
       const grpc::string method_implementation_constructor =
-          grpc::string(method->client_streaming() ? "stream_" : "unary_") +
-          grpc::string(method->server_streaming() ? "stream_" : "unary_") +
+          grpc::string(method->ClientStreaming() ? "stream_" : "unary_") +
+          grpc::string(method->ServerStreaming() ? "stream_" : "unary_") +
           "inline";
       grpc::string input_message_module_and_class;
-      if (!GetModuleAndMessagePath(method->input_type(),
-                                   &input_message_module_and_class)) {
+      if (!method->get_module_and_message_path_input(
+              &input_message_module_and_class, generator_file_name,
+              generate_in_pb2_grpc, config.import_prefix)) {
         return false;
       }
       grpc::string output_message_module_and_class;
-      if (!GetModuleAndMessagePath(method->output_type(),
-                                   &output_message_module_and_class)) {
+      if (!method->get_module_and_message_path_output(
+              &output_message_module_and_class, generator_file_name,
+              generate_in_pb2_grpc, config.import_prefix)) {
         return false;
       }
       method_implementation_constructors.insert(
@@ -338,19 +237,21 @@
       output_message_modules_and_classes.insert(
           make_pair(method->name(), output_message_module_and_class));
     }
+    StringMap method_dict;
+    method_dict["PackageQualifiedServiceName"] = package_qualified_service_name;
     out->Print("request_deserializers = {\n");
     for (StringMap::iterator name_and_input_module_class_pair =
              input_message_modules_and_classes.begin();
          name_and_input_module_class_pair !=
          input_message_modules_and_classes.end();
          name_and_input_module_class_pair++) {
+      method_dict["MethodName"] = name_and_input_module_class_pair->first;
+      method_dict["InputTypeModuleAndClass"] =
+          name_and_input_module_class_pair->second;
       IndentScope raii_indent(out);
-      out->Print(
-          "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
-          "$InputTypeModuleAndClass$.FromString,\n",
-          "PackageQualifiedServiceName", package_qualified_service_name,
-          "MethodName", name_and_input_module_class_pair->first,
-          "InputTypeModuleAndClass", name_and_input_module_class_pair->second);
+      out->Print(method_dict,
+                 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+                 "$InputTypeModuleAndClass$.FromString,\n");
     }
     out->Print("}\n");
     out->Print("response_serializers = {\n");
@@ -359,14 +260,13 @@
          name_and_output_module_class_pair !=
          output_message_modules_and_classes.end();
          name_and_output_module_class_pair++) {
+      method_dict["MethodName"] = name_and_output_module_class_pair->first;
+      method_dict["OutputTypeModuleAndClass"] =
+          name_and_output_module_class_pair->second;
       IndentScope raii_indent(out);
-      out->Print(
-          "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
-          "$OutputTypeModuleAndClass$.SerializeToString,\n",
-          "PackageQualifiedServiceName", package_qualified_service_name,
-          "MethodName", name_and_output_module_class_pair->first,
-          "OutputTypeModuleAndClass",
-          name_and_output_module_class_pair->second);
+      out->Print(method_dict,
+                 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+                 "$OutputTypeModuleAndClass$.SerializeToString,\n");
     }
     out->Print("}\n");
     out->Print("method_implementations = {\n");
@@ -375,15 +275,14 @@
          name_and_implementation_constructor !=
          method_implementation_constructors.end();
          name_and_implementation_constructor++) {
+      method_dict["Method"] = name_and_implementation_constructor->first;
+      method_dict["Constructor"] = name_and_implementation_constructor->second;
       IndentScope raii_descriptions_indent(out);
       const grpc::string method_name =
           name_and_implementation_constructor->first;
-      out->Print(
-          "(\'$PackageQualifiedServiceName$\', \'$Method$\'): "
-          "face_utilities.$Constructor$(servicer.$Method$),\n",
-          "PackageQualifiedServiceName", package_qualified_service_name,
-          "Method", name_and_implementation_constructor->first, "Constructor",
-          name_and_implementation_constructor->second);
+      out->Print(method_dict,
+                 "(\'$PackageQualifiedServiceName$\', \'$Method$\'): "
+                 "face_utilities.$Constructor$(servicer.$Method$),\n");
     }
     out->Print("}\n");
     out->Print(
@@ -402,7 +301,7 @@
 
 bool PrivateGenerator::PrintBetaStubFactory(
     const grpc::string& package_qualified_service_name,
-    const ServiceDescriptor* service) {
+    const grpc_generator::Service* service, grpc_generator::Printer* out) {
   StringMap dict;
   dict["Service"] = service->name();
   out->Print("\n\n");
@@ -421,18 +320,20 @@
     StringMap input_message_modules_and_classes;
     StringMap output_message_modules_and_classes;
     for (int i = 0; i < service->method_count(); ++i) {
-      const MethodDescriptor* method = service->method(i);
+      auto method = service->method(i);
       const grpc::string method_cardinality =
-          grpc::string(method->client_streaming() ? "STREAM" : "UNARY") + "_" +
-          grpc::string(method->server_streaming() ? "STREAM" : "UNARY");
+          grpc::string(method->ClientStreaming() ? "STREAM" : "UNARY") + "_" +
+          grpc::string(method->ServerStreaming() ? "STREAM" : "UNARY");
       grpc::string input_message_module_and_class;
-      if (!GetModuleAndMessagePath(method->input_type(),
-                                   &input_message_module_and_class)) {
+      if (!method->get_module_and_message_path_input(
+              &input_message_module_and_class, generator_file_name,
+              generate_in_pb2_grpc, config.import_prefix)) {
         return false;
       }
       grpc::string output_message_module_and_class;
-      if (!GetModuleAndMessagePath(method->output_type(),
-                                   &output_message_module_and_class)) {
+      if (!method->get_module_and_message_path_output(
+              &output_message_module_and_class, generator_file_name,
+              generate_in_pb2_grpc, config.import_prefix)) {
         return false;
       }
       method_cardinalities.insert(
@@ -442,19 +343,21 @@
       output_message_modules_and_classes.insert(
           make_pair(method->name(), output_message_module_and_class));
     }
+    StringMap method_dict;
+    method_dict["PackageQualifiedServiceName"] = package_qualified_service_name;
     out->Print("request_serializers = {\n");
     for (StringMap::iterator name_and_input_module_class_pair =
              input_message_modules_and_classes.begin();
          name_and_input_module_class_pair !=
          input_message_modules_and_classes.end();
          name_and_input_module_class_pair++) {
+      method_dict["MethodName"] = name_and_input_module_class_pair->first;
+      method_dict["InputTypeModuleAndClass"] =
+          name_and_input_module_class_pair->second;
       IndentScope raii_indent(out);
-      out->Print(
-          "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
-          "$InputTypeModuleAndClass$.SerializeToString,\n",
-          "PackageQualifiedServiceName", package_qualified_service_name,
-          "MethodName", name_and_input_module_class_pair->first,
-          "InputTypeModuleAndClass", name_and_input_module_class_pair->second);
+      out->Print(method_dict,
+                 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+                 "$InputTypeModuleAndClass$.SerializeToString,\n");
     }
     out->Print("}\n");
     out->Print("response_deserializers = {\n");
@@ -463,14 +366,13 @@
          name_and_output_module_class_pair !=
          output_message_modules_and_classes.end();
          name_and_output_module_class_pair++) {
+      method_dict["MethodName"] = name_and_output_module_class_pair->first;
+      method_dict["OutputTypeModuleAndClass"] =
+          name_and_output_module_class_pair->second;
       IndentScope raii_indent(out);
-      out->Print(
-          "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
-          "$OutputTypeModuleAndClass$.FromString,\n",
-          "PackageQualifiedServiceName", package_qualified_service_name,
-          "MethodName", name_and_output_module_class_pair->first,
-          "OutputTypeModuleAndClass",
-          name_and_output_module_class_pair->second);
+      out->Print(method_dict,
+                 "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+                 "$OutputTypeModuleAndClass$.FromString,\n");
     }
     out->Print("}\n");
     out->Print("cardinalities = {\n");
@@ -478,10 +380,11 @@
              method_cardinalities.begin();
          name_and_cardinality != method_cardinalities.end();
          name_and_cardinality++) {
+      method_dict["Method"] = name_and_cardinality->first;
+      method_dict["Cardinality"] = name_and_cardinality->second;
       IndentScope raii_descriptions_indent(out);
-      out->Print("\'$Method$\': cardinality.Cardinality.$Cardinality$,\n",
-                 "Method", name_and_cardinality->first, "Cardinality",
-                 name_and_cardinality->second);
+      out->Print(method_dict,
+                 "\'$Method$\': cardinality.Cardinality.$Cardinality$,\n");
     }
     out->Print("}\n");
     out->Print(
@@ -490,23 +393,25 @@
         "request_serializers=request_serializers, "
         "response_deserializers=response_deserializers, "
         "thread_pool=pool, thread_pool_size=pool_size)\n");
-    out->Print(
-        "return beta_implementations.dynamic_stub(channel, "
-        "\'$PackageQualifiedServiceName$\', "
-        "cardinalities, options=stub_options)\n",
-        "PackageQualifiedServiceName", package_qualified_service_name);
+    out->Print(method_dict,
+               "return beta_implementations.dynamic_stub(channel, "
+               "\'$PackageQualifiedServiceName$\', "
+               "cardinalities, options=stub_options)\n");
   }
   return true;
 }
 
 bool PrivateGenerator::PrintStub(
     const grpc::string& package_qualified_service_name,
-    const ServiceDescriptor* service) {
+    const grpc_generator::Service* service, grpc_generator::Printer* out) {
+  StringMap dict;
+  dict["Service"] = service->name();
   out->Print("\n\n");
-  out->Print("class $Service$Stub(object):\n", "Service", service->name());
+  out->Print(dict, "class $Service$Stub(object):\n");
   {
     IndentScope raii_class_indent(out);
-    PrintAllComments(service);
+    StringVector service_comments = service->GetAllComments();
+    PrintAllComments(service_comments, out);
     out->Print("\n");
     out->Print("def __init__(self, channel):\n");
     {
@@ -520,35 +425,41 @@
       }
       out->Print("\"\"\"\n");
       for (int i = 0; i < service->method_count(); ++i) {
-        const MethodDescriptor* method = service->method(i);
+        auto method = service->method(i);
         grpc::string multi_callable_constructor =
-            grpc::string(method->client_streaming() ? "stream" : "unary") +
-            "_" + grpc::string(method->server_streaming() ? "stream" : "unary");
+            grpc::string(method->ClientStreaming() ? "stream" : "unary") + "_" +
+            grpc::string(method->ServerStreaming() ? "stream" : "unary");
         grpc::string request_module_and_class;
-        if (!GetModuleAndMessagePath(method->input_type(),
-                                     &request_module_and_class)) {
+        if (!method->get_module_and_message_path_input(
+                &request_module_and_class, generator_file_name,
+                generate_in_pb2_grpc, config.import_prefix)) {
           return false;
         }
         grpc::string response_module_and_class;
-        if (!GetModuleAndMessagePath(method->output_type(),
-                                     &response_module_and_class)) {
+        if (!method->get_module_and_message_path_output(
+                &response_module_and_class, generator_file_name,
+                generate_in_pb2_grpc, config.import_prefix)) {
           return false;
         }
-        out->Print("self.$Method$ = channel.$MultiCallableConstructor$(\n",
-                   "Method", method->name(), "MultiCallableConstructor",
-                   multi_callable_constructor);
+        StringMap method_dict;
+        method_dict["Method"] = method->name();
+        method_dict["MultiCallableConstructor"] = multi_callable_constructor;
+        out->Print(method_dict,
+                   "self.$Method$ = channel.$MultiCallableConstructor$(\n");
         {
+          method_dict["PackageQualifiedService"] =
+              package_qualified_service_name;
+          method_dict["RequestModuleAndClass"] = request_module_and_class;
+          method_dict["ResponseModuleAndClass"] = response_module_and_class;
           IndentScope raii_first_attribute_indent(out);
           IndentScope raii_second_attribute_indent(out);
-          out->Print("'/$PackageQualifiedService$/$Method$',\n",
-                     "PackageQualifiedService", package_qualified_service_name,
-                     "Method", method->name());
+          out->Print(method_dict, "'/$PackageQualifiedService$/$Method$',\n");
+          out->Print(method_dict,
+                     "request_serializer=$RequestModuleAndClass$."
+                     "SerializeToString,\n");
           out->Print(
-              "request_serializer=$RequestModuleAndClass$.SerializeToString,\n",
-              "RequestModuleAndClass", request_module_and_class);
-          out->Print(
-              "response_deserializer=$ResponseModuleAndClass$.FromString,\n",
-              "ResponseModuleAndClass", response_module_and_class);
+              method_dict,
+              "response_deserializer=$ResponseModuleAndClass$.FromString,\n");
           out->Print(")\n");
         }
       }
@@ -557,22 +468,29 @@
   return true;
 }
 
-bool PrivateGenerator::PrintServicer(const ServiceDescriptor* service) {
+bool PrivateGenerator::PrintServicer(const grpc_generator::Service* service,
+                                     grpc_generator::Printer* out) {
+  StringMap service_dict;
+  service_dict["Service"] = service->name();
   out->Print("\n\n");
-  out->Print("class $Service$Servicer(object):\n", "Service", service->name());
+  out->Print(service_dict, "class $Service$Servicer(object):\n");
   {
     IndentScope raii_class_indent(out);
-    PrintAllComments(service);
+    StringVector service_comments = service->GetAllComments();
+    PrintAllComments(service_comments, out);
     for (int i = 0; i < service->method_count(); ++i) {
-      const MethodDescriptor* method = service->method(i);
+      auto method = service->method(i);
       grpc::string arg_name =
-          method->client_streaming() ? "request_iterator" : "request";
+          method->ClientStreaming() ? "request_iterator" : "request";
+      StringMap method_dict;
+      method_dict["Method"] = method->name();
+      method_dict["ArgName"] = arg_name;
       out->Print("\n");
-      out->Print("def $Method$(self, $ArgName$, context):\n", "Method",
-                 method->name(), "ArgName", arg_name);
+      out->Print(method_dict, "def $Method$(self, $ArgName$, context):\n");
       {
         IndentScope raii_method_indent(out);
-        PrintAllComments(method);
+        StringVector method_comments = method->GetAllComments();
+        PrintAllComments(method_comments, out);
         out->Print("context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n");
         out->Print("context.set_details('Method not implemented!')\n");
         out->Print("raise NotImplementedError('Method not implemented!')\n");
@@ -584,10 +502,12 @@
 
 bool PrivateGenerator::PrintAddServicerToServer(
     const grpc::string& package_qualified_service_name,
-    const ServiceDescriptor* service) {
+    const grpc_generator::Service* service, grpc_generator::Printer* out) {
+  StringMap service_dict;
+  service_dict["Service"] = service->name();
   out->Print("\n\n");
-  out->Print("def add_$Service$Servicer_to_server(servicer, server):\n",
-             "Service", service->name());
+  out->Print(service_dict,
+             "def add_$Service$Servicer_to_server(servicer, server):\n");
   {
     IndentScope raii_class_indent(out);
     out->Print("rpc_method_handlers = {\n");
@@ -595,58 +515,66 @@
       IndentScope raii_dict_first_indent(out);
       IndentScope raii_dict_second_indent(out);
       for (int i = 0; i < service->method_count(); ++i) {
-        const MethodDescriptor* method = service->method(i);
+        auto method = service->method(i);
         grpc::string method_handler_constructor =
-            grpc::string(method->client_streaming() ? "stream" : "unary") +
-            "_" +
-            grpc::string(method->server_streaming() ? "stream" : "unary") +
+            grpc::string(method->ClientStreaming() ? "stream" : "unary") + "_" +
+            grpc::string(method->ServerStreaming() ? "stream" : "unary") +
             "_rpc_method_handler";
         grpc::string request_module_and_class;
-        if (!GetModuleAndMessagePath(method->input_type(),
-                                     &request_module_and_class)) {
+        if (!method->get_module_and_message_path_input(
+                &request_module_and_class, generator_file_name,
+                generate_in_pb2_grpc, config.import_prefix)) {
           return false;
         }
         grpc::string response_module_and_class;
-        if (!GetModuleAndMessagePath(method->output_type(),
-                                     &response_module_and_class)) {
+        if (!method->get_module_and_message_path_output(
+                &response_module_and_class, generator_file_name,
+                generate_in_pb2_grpc, config.import_prefix)) {
           return false;
         }
-        out->Print("'$Method$': grpc.$MethodHandlerConstructor$(\n", "Method",
-                   method->name(), "MethodHandlerConstructor",
-                   method_handler_constructor);
+        StringMap method_dict;
+        method_dict["Method"] = method->name();
+        method_dict["MethodHandlerConstructor"] = method_handler_constructor;
+        method_dict["RequestModuleAndClass"] = request_module_and_class;
+        method_dict["ResponseModuleAndClass"] = response_module_and_class;
+        out->Print(method_dict,
+                   "'$Method$': grpc.$MethodHandlerConstructor$(\n");
         {
           IndentScope raii_call_first_indent(out);
           IndentScope raii_call_second_indent(out);
-          out->Print("servicer.$Method$,\n", "Method", method->name());
+          out->Print(method_dict, "servicer.$Method$,\n");
           out->Print(
-              "request_deserializer=$RequestModuleAndClass$.FromString,\n",
-              "RequestModuleAndClass", request_module_and_class);
+              method_dict,
+              "request_deserializer=$RequestModuleAndClass$.FromString,\n");
           out->Print(
+              method_dict,
               "response_serializer=$ResponseModuleAndClass$.SerializeToString,"
-              "\n",
-              "ResponseModuleAndClass", response_module_and_class);
+              "\n");
         }
         out->Print("),\n");
       }
     }
+    StringMap method_dict;
+    method_dict["PackageQualifiedServiceName"] = package_qualified_service_name;
     out->Print("}\n");
     out->Print("generic_handler = grpc.method_handlers_generic_handler(\n");
     {
       IndentScope raii_call_first_indent(out);
       IndentScope raii_call_second_indent(out);
-      out->Print("'$PackageQualifiedServiceName$', rpc_method_handlers)\n",
-                 "PackageQualifiedServiceName", package_qualified_service_name);
+      out->Print(method_dict,
+                 "'$PackageQualifiedServiceName$', rpc_method_handlers)\n");
     }
     out->Print("server.add_generic_rpc_handlers((generic_handler,))\n");
   }
   return true;
 }
 
-bool PrivateGenerator::PrintBetaPreamble() {
-  out->Print("from $Package$ import implementations as beta_implementations\n",
-             "Package", config.beta_package_root);
-  out->Print("from $Package$ import interfaces as beta_interfaces\n", "Package",
-             config.beta_package_root);
+bool PrivateGenerator::PrintBetaPreamble(grpc_generator::Printer* out) {
+  StringMap var;
+  var["Package"] = config.beta_package_root;
+  out->Print(var,
+             "from $Package$ import implementations as beta_implementations\n");
+  out->Print(var, "from $Package$ import interfaces as beta_interfaces\n");
   out->Print("from grpc.framework.common import cardinality\n");
   out->Print(
       "from grpc.framework.interfaces.face import utilities as "
@@ -654,65 +582,78 @@
   return true;
 }
 
-bool PrivateGenerator::PrintPreamble() {
-  out->Print("import $Package$\n", "Package", config.grpc_package_root);
+bool PrivateGenerator::PrintPreamble(grpc_generator::Printer* out) {
+  StringMap var;
+  var["Package"] = config.grpc_package_root;
+  out->Print(var, "import $Package$\n");
   if (generate_in_pb2_grpc) {
     out->Print("\n");
     StringPairSet imports_set;
     for (int i = 0; i < file->service_count(); ++i) {
-      const ServiceDescriptor* service = file->service(i);
+      auto service = file->service(i);
       for (int j = 0; j < service->method_count(); ++j) {
-        const MethodDescriptor* method = service->method(j);
-        const Descriptor* types[2] = {method->input_type(),
-                                      method->output_type()};
-        for (int k = 0; k < 2; ++k) {
-          const Descriptor* type = types[k];
-          grpc::string type_file_name = type->file()->name();
-          grpc::string module_name =
-              ModuleName(type_file_name, config.import_prefix);
-          grpc::string module_alias =
-              ModuleAlias(type_file_name, config.import_prefix);
-          imports_set.insert(std::make_tuple(module_name, module_alias));
-        }
+        auto method = service.get()->method(j);
+
+        grpc::string input_type_file_name = method->get_input_type_name();
+        grpc::string input_module_name =
+            ModuleName(input_type_file_name, config.import_prefix);
+        grpc::string input_module_alias =
+            ModuleAlias(input_type_file_name, config.import_prefix);
+        imports_set.insert(
+            std::make_tuple(input_module_name, input_module_alias));
+
+        grpc::string output_type_file_name = method->get_output_type_name();
+        grpc::string output_module_name =
+            ModuleName(output_type_file_name, config.import_prefix);
+        grpc::string output_module_alias =
+            ModuleAlias(output_type_file_name, config.import_prefix);
+        imports_set.insert(
+            std::make_tuple(output_module_name, output_module_alias));
       }
     }
+
     for (StringPairSet::iterator it = imports_set.begin();
          it != imports_set.end(); ++it) {
-      out->Print("import $ModuleName$ as $ModuleAlias$\n", "ModuleName",
-                 std::get<0>(*it), "ModuleAlias", std::get<1>(*it));
+      var["ModuleName"] = std::get<0>(*it);
+      var["ModuleAlias"] = std::get<1>(*it);
+      out->Print(var, "import $ModuleName$ as $ModuleAlias$\n");
     }
   }
   return true;
 }
 
-bool PrivateGenerator::PrintGAServices() {
+bool PrivateGenerator::PrintGAServices(grpc_generator::Printer* out) {
   grpc::string package = file->package();
   if (!package.empty()) {
     package = package.append(".");
   }
   for (int i = 0; i < file->service_count(); ++i) {
-    const ServiceDescriptor* service = file->service(i);
+    auto service = file->service(i);
     grpc::string package_qualified_service_name = package + service->name();
-    if (!(PrintStub(package_qualified_service_name, service) &&
-          PrintServicer(service) &&
-          PrintAddServicerToServer(package_qualified_service_name, service))) {
+    if (!(PrintStub(package_qualified_service_name, service.get(), out) &&
+          PrintServicer(service.get(), out) &&
+          PrintAddServicerToServer(package_qualified_service_name,
+                                   service.get(), out))) {
       return false;
     }
   }
   return true;
 }
 
-bool PrivateGenerator::PrintBetaServices() {
+bool PrivateGenerator::PrintBetaServices(grpc_generator::Printer* out) {
   grpc::string package = file->package();
   if (!package.empty()) {
     package = package.append(".");
   }
   for (int i = 0; i < file->service_count(); ++i) {
-    const ServiceDescriptor* service = file->service(i);
+    auto service = file->service(i);
     grpc::string package_qualified_service_name = package + service->name();
-    if (!(PrintBetaServicer(service) && PrintBetaStub(service) &&
-          PrintBetaServerFactory(package_qualified_service_name, service) &&
-          PrintBetaStubFactory(package_qualified_service_name, service))) {
+    if (!(PrintBetaServicer(service.get(), out) &&
+          PrintBetaStub(service.get(), out) &&
+          PrintBetaServerFactory(package_qualified_service_name, service.get(),
+                                 out) &&
+          PrintBetaStubFactory(package_qualified_service_name, service.get(),
+                               out))) {
       return false;
     }
   }
@@ -723,43 +664,40 @@
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
-    StringOutputStream output_stream(&output);
-    Printer out_printer(&output_stream, '$');
-    out = &out_printer;
-
+    auto out = file->CreatePrinter(&output);
     if (generate_in_pb2_grpc) {
       out->Print(
           "# Generated by the gRPC Python protocol compiler plugin. "
           "DO NOT EDIT!\n");
-      if (!PrintPreamble()) {
+      if (!PrintPreamble(out.get())) {
         return make_pair(false, "");
       }
-      if (!PrintGAServices()) {
+      if (!PrintGAServices(out.get())) {
         return make_pair(false, "");
       }
     } else {
       out->Print("try:\n");
       {
-        IndentScope raii_dict_try_indent(out);
+        IndentScope raii_dict_try_indent(out.get());
         out->Print(
             "# THESE ELEMENTS WILL BE DEPRECATED.\n"
             "# Please use the generated *_pb2_grpc.py files instead.\n");
-        if (!PrintPreamble()) {
+        if (!PrintPreamble(out.get())) {
           return make_pair(false, "");
         }
-        if (!PrintBetaPreamble()) {
+        if (!PrintBetaPreamble(out.get())) {
           return make_pair(false, "");
         }
-        if (!PrintGAServices()) {
+        if (!PrintGAServices(out.get())) {
           return make_pair(false, "");
         }
-        if (!PrintBetaServices()) {
+        if (!PrintBetaServices(out.get())) {
           return make_pair(false, "");
         }
       }
       out->Print("except ImportError:\n");
       {
-        IndentScope raii_dict_except_indent(out);
+        IndentScope raii_dict_except_indent(out.get());
         out->Print("pass");
       }
     }
@@ -823,8 +761,10 @@
     *error = "Invalid proto file name. Proto file must end with .proto";
     return false;
   }
+  generator_file_name = file->name();
 
-  PrivateGenerator generator(config_, file);
+  ProtoBufFile pbfile(file);
+  PrivateGenerator generator(config_, &pbfile);
   if (parameter == "grpc_2_0") {
     return GenerateGrpc(context, generator, pb2_grpc_file_name, true);
   } else if (parameter == "") {
diff --git a/src/compiler/python_generator.h b/src/compiler/python_generator.h
index b91059f..0c0d744 100644
--- a/src/compiler/python_generator.h
+++ b/src/compiler/python_generator.h
@@ -37,6 +37,7 @@
 #include <utility>
 
 #include "src/compiler/config.h"
+#include "src/compiler/schema_interface.h"
 
 namespace grpc_python_generator {
 
diff --git a/src/compiler/python_generator_helpers.h b/src/compiler/python_generator_helpers.h
new file mode 100644
index 0000000..9fca711
--- /dev/null
+++ b/src/compiler/python_generator_helpers.h
@@ -0,0 +1,142 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H
+#define GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H
+
+#include <cstring>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include "src/compiler/config.h"
+#include "src/compiler/generator_helpers.h"
+#include "src/compiler/python_generator.h"
+#include "src/compiler/python_private_generator.h"
+
+using std::vector;
+using grpc_generator::StringReplace;
+using grpc_generator::StripProto;
+using grpc::protobuf::Descriptor;
+using grpc::protobuf::FileDescriptor;
+using grpc::protobuf::MethodDescriptor;
+using grpc::protobuf::ServiceDescriptor;
+using grpc::protobuf::compiler::GeneratorContext;
+using grpc::protobuf::io::CodedOutputStream;
+using grpc::protobuf::io::Printer;
+using grpc::protobuf::io::StringOutputStream;
+using grpc::protobuf::io::ZeroCopyOutputStream;
+
+namespace grpc_python_generator {
+
+namespace {
+
+typedef vector<const Descriptor*> DescriptorVector;
+typedef vector<grpc::string> StringVector;
+
+// TODO(https://github.com/google/protobuf/issues/888):
+// Export `ModuleName` from protobuf's
+// `src/google/protobuf/compiler/python/python_generator.cc` file.
+grpc::string ModuleName(const grpc::string& filename,
+                        const grpc::string& import_prefix) {
+  grpc::string basename = StripProto(filename);
+  basename = StringReplace(basename, "-", "_");
+  basename = StringReplace(basename, "/", ".");
+  return import_prefix + basename + "_pb2";
+}
+
+// TODO(https://github.com/google/protobuf/issues/888):
+// Export `ModuleAlias` from protobuf's
+// `src/google/protobuf/compiler/python/python_generator.cc` file.
+grpc::string ModuleAlias(const grpc::string& filename,
+                         const grpc::string& import_prefix) {
+  grpc::string module_name = ModuleName(filename, import_prefix);
+  // We can't have dots in the module name, so we replace each with _dot_.
+  // But that could lead to a collision between a.b and a_dot_b, so we also
+  // duplicate each underscore.
+  module_name = StringReplace(module_name, "_", "__");
+  module_name = StringReplace(module_name, ".", "_dot_");
+  return module_name;
+}
+
+bool GetModuleAndMessagePath(const Descriptor* type, grpc::string* out,
+                             grpc::string generator_file_name,
+                             bool generate_in_pb2_grpc,
+                             grpc::string& import_prefix) {
+  const Descriptor* path_elem_type = type;
+  DescriptorVector message_path;
+  do {
+    message_path.push_back(path_elem_type);
+    path_elem_type = path_elem_type->containing_type();
+  } while (path_elem_type);  // implicit nullptr comparison; don't be explicit
+  grpc::string file_name = type->file()->name();
+  static const int proto_suffix_length = strlen(".proto");
+  if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) &&
+        file_name.find_last_of(".proto") == file_name.size() - 1)) {
+    return false;
+  }
+
+  grpc::string module;
+  if (generator_file_name != file_name || generate_in_pb2_grpc) {
+    module = ModuleAlias(file_name, import_prefix) + ".";
+  } else {
+    module = "";
+  }
+  grpc::string message_type;
+  for (DescriptorVector::reverse_iterator path_iter = message_path.rbegin();
+       path_iter != message_path.rend(); ++path_iter) {
+    message_type += (*path_iter)->name() + ".";
+  }
+  // no pop_back prior to C++11
+  message_type.resize(message_type.size() - 1);
+  *out = module + message_type;
+  return true;
+}
+
+template <typename DescriptorType>
+StringVector get_all_comments(const DescriptorType* descriptor) {
+  StringVector comments;
+  grpc_generator::GetComment(
+      descriptor, grpc_generator::COMMENTTYPE_LEADING_DETACHED, &comments);
+  grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_LEADING,
+                             &comments);
+  grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_TRAILING,
+                             &comments);
+  return comments;
+}
+
+}  // namespace
+
+}  // namespace grpc_python_generator
+
+#endif  // GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H
diff --git a/src/compiler/python_plugin.cc b/src/compiler/python_plugin.cc
index 3457aa6..f34abcc 100644
--- a/src/compiler/python_plugin.cc
+++ b/src/compiler/python_plugin.cc
@@ -34,6 +34,7 @@
 // Generates a Python gRPC service interface out of Protobuf IDL.
 
 #include "src/compiler/config.h"
+#include "src/compiler/protobuf_plugin.h"
 #include "src/compiler/python_generator.h"
 
 int main(int argc, char* argv[]) {
diff --git a/src/compiler/python_private_generator.h b/src/compiler/python_private_generator.h
new file mode 100644
index 0000000..d20ff51
--- /dev/null
+++ b/src/compiler/python_private_generator.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H
+#define GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H
+
+#include <iostream>
+#include <vector>
+
+#include "src/compiler/python_generator.h"
+#include "src/compiler/schema_interface.h"
+
+namespace grpc_python_generator {
+
+namespace {
+
+// Tucks all generator state in an anonymous namespace away from
+// PythonGrpcGenerator and the header file, mostly to encourage future changes
+// to not require updates to the grpcio-tools C++ code part. Assumes that it is
+// only ever used from a single thread.
+struct PrivateGenerator {
+  const GeneratorConfiguration& config;
+  const grpc_generator::File* file;
+
+  bool generate_in_pb2_grpc;
+
+  PrivateGenerator(const GeneratorConfiguration& config,
+                   const grpc_generator::File* file);
+
+  std::pair<bool, grpc::string> GetGrpcServices();
+
+ private:
+  bool PrintPreamble(grpc_generator::Printer* out);
+  bool PrintBetaPreamble(grpc_generator::Printer* out);
+  bool PrintGAServices(grpc_generator::Printer* out);
+  bool PrintBetaServices(grpc_generator::Printer* out);
+
+  bool PrintAddServicerToServer(
+      const grpc::string& package_qualified_service_name,
+      const grpc_generator::Service* service, grpc_generator::Printer* out);
+  bool PrintServicer(const grpc_generator::Service* service,
+                     grpc_generator::Printer* out);
+  bool PrintStub(const grpc::string& package_qualified_service_name,
+                 const grpc_generator::Service* service,
+                 grpc_generator::Printer* out);
+
+  bool PrintBetaServicer(const grpc_generator::Service* service,
+                         grpc_generator::Printer* out);
+  bool PrintBetaServerFactory(
+      const grpc::string& package_qualified_service_name,
+      const grpc_generator::Service* service, grpc_generator::Printer* out);
+  bool PrintBetaStub(const grpc_generator::Service* service,
+                     grpc_generator::Printer* out);
+  bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name,
+                            const grpc_generator::Service* service,
+                            grpc_generator::Printer* out);
+
+  // Get all comments (leading, leading_detached, trailing) and print them as a
+  // docstring. Any leading space of a line will be removed, but the line
+  // wrapping will not be changed.
+  void PrintAllComments(std::vector<grpc::string> comments,
+                        grpc_generator::Printer* out);
+};
+
+}  // namespace
+
+}  // namespace grpc_python_generator
+
+#endif  // GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H
diff --git a/src/compiler/schema_interface.h b/src/compiler/schema_interface.h
new file mode 100644
index 0000000..25bbdb5
--- /dev/null
+++ b/src/compiler/schema_interface.h
@@ -0,0 +1,126 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
+#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
+
+#include "src/compiler/config.h"
+
+#include <memory>
+#include <vector>
+
+#ifndef GRPC_CUSTOM_STRING
+#include <string>
+#define GRPC_CUSTOM_STRING std::string
+#endif
+
+namespace grpc {
+
+typedef GRPC_CUSTOM_STRING string;
+
+}  // namespace grpc
+
+namespace grpc_generator {
+
+// A common interface for objects having comments in the source.
+// Return formatted comments to be inserted in generated code.
+struct CommentHolder {
+  virtual ~CommentHolder() {}
+  virtual grpc::string GetLeadingComments(const grpc::string prefix) const = 0;
+  virtual grpc::string GetTrailingComments(const grpc::string prefix) const = 0;
+  virtual std::vector<grpc::string> GetAllComments() const = 0;
+};
+
+// An abstract interface representing a method.
+struct Method : public CommentHolder {
+  virtual ~Method() {}
+
+  virtual grpc::string name() const = 0;
+
+  virtual grpc::string input_type_name() const = 0;
+  virtual grpc::string output_type_name() const = 0;
+
+  virtual bool get_module_and_message_path_input(
+      grpc::string *str, grpc::string generator_file_name,
+      bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
+  virtual bool get_module_and_message_path_output(
+      grpc::string *str, grpc::string generator_file_name,
+      bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
+
+  virtual grpc::string get_input_type_name() const = 0;
+  virtual grpc::string get_output_type_name() const = 0;
+  virtual bool NoStreaming() const = 0;
+  virtual bool ClientStreaming() const = 0;
+  virtual bool ServerStreaming() const = 0;
+  virtual bool BidiStreaming() const = 0;
+};
+
+// An abstract interface representing a service.
+struct Service : public CommentHolder {
+  virtual ~Service() {}
+
+  virtual grpc::string name() const = 0;
+
+  virtual int method_count() const = 0;
+  virtual std::unique_ptr<const Method> method(int i) const = 0;
+};
+
+struct Printer {
+  virtual ~Printer() {}
+
+  virtual void Print(const std::map<grpc::string, grpc::string> &vars,
+                     const char *template_string) = 0;
+  virtual void Print(const char *string) = 0;
+  virtual void Indent() = 0;
+  virtual void Outdent() = 0;
+};
+
+// An interface that allows the source generated to be output using various
+// libraries/idls/serializers.
+struct File : public CommentHolder {
+  virtual ~File() {}
+
+  virtual grpc::string filename() const = 0;
+  virtual grpc::string filename_without_ext() const = 0;
+  virtual grpc::string package() const = 0;
+  virtual std::vector<grpc::string> package_parts() const = 0;
+  virtual grpc::string additional_headers() const = 0;
+
+  virtual int service_count() const = 0;
+  virtual std::unique_ptr<const Service> service(int i) const = 0;
+
+  virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0;
+};
+}  // namespace grpc_generator
+
+#endif  // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
diff --git a/src/core/ext/census/gen/trace_context.pb.h b/src/core/ext/census/gen/trace_context.pb.h
index ea127bf..6fafc04 100644
--- a/src/core/ext/census/gen/trace_context.pb.h
+++ b/src/core/ext/census/gen/trace_context.pb.h
@@ -90,4 +90,4 @@
 #endif
 /* @@protoc_insertion_point(eof) */
 
-#endif
+#endif /* GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H */
diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c
index fc29dbd..bcf59a4 100644
--- a/src/core/ext/census/grpc_filter.c
+++ b/src/core/ext/census/grpc_filter.c
@@ -74,17 +74,18 @@
 }
 
 static void client_mutate_op(grpc_call_element *elem,
-                             grpc_transport_stream_op *op) {
+                             grpc_transport_stream_op_batch *op) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   if (op->send_initial_metadata) {
-    extract_and_annotate_method_tag(op->send_initial_metadata, calld, chand);
+    extract_and_annotate_method_tag(
+        op->payload->send_initial_metadata.send_initial_metadata, calld, chand);
   }
 }
 
 static void client_start_transport_op(grpc_exec_ctx *exec_ctx,
                                       grpc_call_element *elem,
-                                      grpc_transport_stream_op *op) {
+                                      grpc_transport_stream_op_batch *op) {
   client_mutate_op(elem, op);
   grpc_call_next_op(exec_ctx, elem, op);
 }
@@ -103,19 +104,22 @@
 }
 
 static void server_mutate_op(grpc_call_element *elem,
-                             grpc_transport_stream_op *op) {
+                             grpc_transport_stream_op_batch *op) {
   call_data *calld = elem->call_data;
   if (op->recv_initial_metadata) {
     /* substitute our callback for the op callback */
-    calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = &calld->finish_recv;
+    calld->recv_initial_metadata =
+        op->payload->recv_initial_metadata.recv_initial_metadata;
+    calld->on_done_recv =
+        op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+    op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+        &calld->finish_recv;
   }
 }
 
 static void server_start_transport_op(grpc_exec_ctx *exec_ctx,
                                       grpc_call_element *elem,
-                                      grpc_transport_stream_op *op) {
+                                      grpc_transport_stream_op_batch *op) {
   /* TODO(ctiller): this code fails. I don't know why. I expect it's
                     incomplete, and someone should look at it soon.
 
diff --git a/src/core/ext/census/grpc_plugin.c b/src/core/ext/census/grpc_plugin.c
index c9fe453..28d266e 100644
--- a/src/core/ext/census/grpc_plugin.c
+++ b/src/core/ext/census/grpc_plugin.c
@@ -48,7 +48,7 @@
       return a->args[i].value.integer != 0 && census_enabled();
     }
   }
-  return census_enabled();
+  return census_enabled() && !grpc_channel_args_want_minimal_stack(a);
 }
 
 static bool maybe_add_census_filter(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/ext/census/trace_label.h b/src/core/ext/census/trace_label.h
index 0e4a8d8..701f6f5 100644
--- a/src/core/ext/census/trace_label.h
+++ b/src/core/ext/census/trace_label.h
@@ -58,4 +58,4 @@
   } value;
 } trace_label;
 
-#endif
+#endif /* GRPC_CORE_EXT_CENSUS_TRACE_LABEL_H */
diff --git a/src/core/ext/census/trace_propagation.h b/src/core/ext/census/trace_propagation.h
index 75c4eba..0c27bfa 100644
--- a/src/core/ext/census/trace_propagation.h
+++ b/src/core/ext/census/trace_propagation.h
@@ -60,4 +60,4 @@
 size_t http_format_to_trace_span_context(const char *buf, size_t buf_size,
                                          trace_span_context *ctxt);
 
-#endif
+#endif /* GRPC_CORE_EXT_CENSUS_TRACE_PROPAGATION_H */
diff --git a/src/core/ext/census/trace_status.h b/src/core/ext/census/trace_status.h
index adc0ebd..0734ec6 100644
--- a/src/core/ext/census/trace_status.h
+++ b/src/core/ext/census/trace_status.h
@@ -42,4 +42,4 @@
   trace_string errorMessage;
 } trace_status;
 
-#endif
+#endif /* GRPC_CORE_EXT_CENSUS_TRACE_STATUS_H */
diff --git a/src/core/ext/census/trace_string.h b/src/core/ext/census/trace_string.h
index 8e77ee9..cd63cfb 100644
--- a/src/core/ext/census/trace_string.h
+++ b/src/core/ext/census/trace_string.h
@@ -47,4 +47,4 @@
   size_t length;
 } trace_string;
 
-#endif
+#endif /* GRPC_CORE_EXT_CENSUS_TRACE_STRING_H */
diff --git a/src/core/ext/census/tracing.h b/src/core/ext/census/tracing.h
index c2b947a..3a7c6f4 100644
--- a/src/core/ext/census/tracing.h
+++ b/src/core/ext/census/tracing.h
@@ -121,4 +121,4 @@
 optionally be NULL. */
 void trace_end_span(const trace_status *status, trace_span_context *span_ctxt);
 
-#endif
+#endif /* GRPC_CORE_EXT_CENSUS_TRACING_H */
diff --git a/src/core/ext/client_channel/README.md b/src/core/ext/filters/client_channel/README.md
similarity index 100%
rename from src/core/ext/client_channel/README.md
rename to src/core/ext/filters/client_channel/README.md
diff --git a/src/core/ext/client_channel/channel_connectivity.c b/src/core/ext/filters/client_channel/channel_connectivity.c
similarity index 98%
rename from src/core/ext/client_channel/channel_connectivity.c
rename to src/core/ext/filters/client_channel/channel_connectivity.c
index f6cb3b9..62f58fb 100644
--- a/src/core/ext/client_channel/channel_connectivity.c
+++ b/src/core/ext/filters/client_channel/channel_connectivity.c
@@ -36,7 +36,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/completion_queue.h"
diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/filters/client_channel/client_channel.c
similarity index 91%
rename from src/core/ext/client_channel/client_channel.c
rename to src/core/ext/filters/client_channel/client_channel.c
index 435a3ab..83e3b8f 100644
--- a/src/core/ext/client_channel/client_channel.c
+++ b/src/core/ext/filters/client_channel/client_channel.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 
 #include <stdbool.h>
 #include <stdio.h>
@@ -43,12 +43,12 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/ext/client_channel/http_connect_handshaker.h"
-#include "src/core/ext/client_channel/lb_policy_registry.h"
-#include "src/core/ext/client_channel/proxy_mapper_registry.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
-#include "src/core/ext/client_channel/retry_throttle.h"
-#include "src/core/ext/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/retry_throttle.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/channel/deadline_filter.h"
@@ -374,8 +374,7 @@
     // resolver actually specified.
     channel_arg =
         grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
-    if (channel_arg != NULL) {
-      GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
+    if (channel_arg != NULL && channel_arg->type == GRPC_ARG_POINTER) {
       grpc_lb_addresses *addresses = channel_arg->value.pointer.p;
       bool found_backend_address = false;
       for (size_t i = 0; i < addresses->num_addresses; ++i) {
@@ -533,7 +532,7 @@
 static void start_transport_op_locked(grpc_exec_ctx *exec_ctx, void *arg,
                                       grpc_error *error_ignored) {
   grpc_transport_op *op = arg;
-  grpc_channel_element *elem = op->transport_private.args[0];
+  grpc_channel_element *elem = op->handler_private.extra_arg;
   channel_data *chand = elem->channel_data;
 
   if (op->on_connectivity_state_change != NULL) {
@@ -595,12 +594,12 @@
                                  op->bind_pollset);
   }
 
-  op->transport_private.args[0] = elem;
+  op->handler_private.extra_arg = elem;
   GRPC_CHANNEL_STACK_REF(chand->owning_stack, "start_transport_op");
   grpc_closure_sched(
-      exec_ctx, grpc_closure_init(
-                    &op->transport_private.closure, start_transport_op_locked,
-                    op, grpc_combiner_scheduler(chand->combiner, false)),
+      exec_ctx,
+      grpc_closure_init(&op->handler_private.closure, start_transport_op_locked,
+                        op, grpc_combiner_scheduler(chand->combiner, false)),
       GRPC_ERROR_NONE);
 }
 
@@ -643,14 +642,26 @@
   // Record client channel factory.
   const grpc_arg *arg = grpc_channel_args_find(args->channel_args,
                                                GRPC_ARG_CLIENT_CHANNEL_FACTORY);
-  GPR_ASSERT(arg != NULL);
-  GPR_ASSERT(arg->type == GRPC_ARG_POINTER);
+  if (arg == NULL) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "Missing client channel factory in args for client channel filter");
+  }
+  if (arg->type != GRPC_ARG_POINTER) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "client channel factory arg must be a pointer");
+  }
   grpc_client_channel_factory_ref(arg->value.pointer.p);
   chand->client_channel_factory = arg->value.pointer.p;
   // Get server name to resolve, using proxy mapper if needed.
   arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVER_URI);
-  GPR_ASSERT(arg != NULL);
-  GPR_ASSERT(arg->type == GRPC_ARG_STRING);
+  if (arg == NULL) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "Missing server uri in args for client channel filter");
+  }
+  if (arg->type != GRPC_ARG_STRING) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "server uri arg must be a string");
+  }
   char *proxy_name = NULL;
   grpc_channel_args *new_args = NULL;
   grpc_proxy_mappers_map_name(exec_ctx, arg->value.string, args->channel_args,
@@ -755,7 +766,7 @@
   grpc_connected_subchannel *connected_subchannel;
   grpc_polling_entity *pollent;
 
-  grpc_transport_stream_op **waiting_ops;
+  grpc_transport_stream_op_batch **waiting_ops;
   size_t waiting_ops_count;
   size_t waiting_ops_capacity;
 
@@ -775,7 +786,8 @@
   return scc == CANCELLED_CALL ? NULL : scc;
 }
 
-static void add_waiting_locked(call_data *calld, grpc_transport_stream_op *op) {
+static void add_waiting_locked(call_data *calld,
+                               grpc_transport_stream_op_batch *op) {
   GPR_TIMER_BEGIN("add_waiting_locked", 0);
   if (calld->waiting_ops_count == calld->waiting_ops_capacity) {
     calld->waiting_ops_capacity = GPR_MAX(3, 2 * calld->waiting_ops_capacity);
@@ -791,7 +803,7 @@
                         grpc_error *error) {
   size_t i;
   for (i = 0; i < calld->waiting_ops_count; i++) {
-    grpc_transport_stream_op_finish_with_failure(
+    grpc_transport_stream_op_batch_finish_with_failure(
         exec_ctx, calld->waiting_ops[i], GRPC_ERROR_REF(error));
   }
   calld->waiting_ops_count = 0;
@@ -804,7 +816,7 @@
   }
 
   grpc_subchannel_call *call = GET_CALL(calld);
-  grpc_transport_stream_op **ops = calld->waiting_ops;
+  grpc_transport_stream_op_batch **ops = calld->waiting_ops;
   size_t nops = calld->waiting_ops_count;
   if (call == CANCELLED_CALL) {
     fail_locked(exec_ctx, calld, GRPC_ERROR_CANCELLED);
@@ -902,14 +914,14 @@
         .arena = calld->arena};
     grpc_error *new_error = grpc_connected_subchannel_create_call(
         exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
-    if (new_error != GRPC_ERROR_NONE) {
-      new_error = grpc_error_add_child(new_error, error);
-      subchannel_call = CANCELLED_CALL;
-      fail_locked(exec_ctx, calld, new_error);
-    }
     gpr_atm_rel_store(&calld->subchannel_call,
                       (gpr_atm)(uintptr_t)subchannel_call);
-    retry_waiting_locked(exec_ctx, calld);
+    if (new_error != GRPC_ERROR_NONE) {
+      new_error = grpc_error_add_child(new_error, error);
+      fail_locked(exec_ctx, calld, new_error);
+    } else {
+      retry_waiting_locked(exec_ctx, calld);
+    }
   }
   GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel");
 }
@@ -1052,9 +1064,9 @@
   return false;
 }
 
-static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
-                                                   grpc_transport_stream_op *op,
-                                                   grpc_call_element *elem) {
+static void start_transport_stream_op_batch_locked_inner(
+    grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *op,
+    grpc_call_element *elem) {
   channel_data *chand = elem->channel_data;
   call_data *calld = elem->call_data;
   grpc_subchannel_call *call;
@@ -1062,7 +1074,7 @@
   /* need to recheck that another thread hasn't set the call */
   call = GET_CALL(calld);
   if (call == CANCELLED_CALL) {
-    grpc_transport_stream_op_finish_with_failure(
+    grpc_transport_stream_op_batch_finish_with_failure(
         exec_ctx, op, GRPC_ERROR_REF(calld->cancel_error));
     /* early out */
     return;
@@ -1073,11 +1085,11 @@
     return;
   }
   /* if this is a cancellation, then we can raise our cancelled flag */
-  if (op->cancel_error != GRPC_ERROR_NONE) {
+  if (op->cancel_stream) {
     if (!gpr_atm_rel_cas(&calld->subchannel_call, 0,
                          (gpr_atm)(uintptr_t)CANCELLED_CALL)) {
       /* recurse to retry */
-      start_transport_stream_op_locked_inner(exec_ctx, op, elem);
+      start_transport_stream_op_batch_locked_inner(exec_ctx, op, elem);
       /* early out */
       return;
     } else {
@@ -1086,27 +1098,29 @@
          cancelled before any ops are passed down (e.g., if the deadline
          is in the past when the call starts), we can return the right
          error to the caller when the first op does get passed down. */
-      calld->cancel_error = GRPC_ERROR_REF(op->cancel_error);
+      calld->cancel_error =
+          GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error);
       switch (calld->creation_phase) {
         case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING:
-          fail_locked(exec_ctx, calld, GRPC_ERROR_REF(op->cancel_error));
+          fail_locked(exec_ctx, calld,
+                      GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error));
           break;
         case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL:
-          pick_subchannel_locked(exec_ctx, elem, NULL, 0,
-                                 &calld->connected_subchannel, NULL,
-                                 GRPC_ERROR_REF(op->cancel_error));
+          pick_subchannel_locked(
+              exec_ctx, elem, NULL, 0, &calld->connected_subchannel, NULL,
+              GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error));
           break;
       }
-      grpc_transport_stream_op_finish_with_failure(
-          exec_ctx, op, GRPC_ERROR_REF(op->cancel_error));
+      grpc_transport_stream_op_batch_finish_with_failure(
+          exec_ctx, op,
+          GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error));
       /* early out */
       return;
     }
   }
   /* if we don't have a subchannel, try to get one */
   if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
-      calld->connected_subchannel == NULL &&
-      op->send_initial_metadata != NULL) {
+      calld->connected_subchannel == NULL && op->send_initial_metadata) {
     calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL;
     grpc_closure_init(&calld->next_step, subchannel_ready_locked, elem,
                       grpc_combiner_scheduler(chand->combiner, true));
@@ -1114,10 +1128,11 @@
     /* If a subchannel is not available immediately, the polling entity from
        call_data should be provided to channel_data's interested_parties, so
        that IO of the lb_policy and resolver could be done under it. */
-    if (pick_subchannel_locked(exec_ctx, elem, op->send_initial_metadata,
-                               op->send_initial_metadata_flags,
-                               &calld->connected_subchannel, &calld->next_step,
-                               GRPC_ERROR_NONE)) {
+    if (pick_subchannel_locked(
+            exec_ctx, elem,
+            op->payload->send_initial_metadata.send_initial_metadata,
+            op->payload->send_initial_metadata.send_initial_metadata_flags,
+            &calld->connected_subchannel, &calld->next_step, GRPC_ERROR_NONE)) {
       calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
       GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel");
     } else {
@@ -1137,16 +1152,16 @@
         .arena = calld->arena};
     grpc_error *error = grpc_connected_subchannel_create_call(
         exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
-    if (error != GRPC_ERROR_NONE) {
-      subchannel_call = CANCELLED_CALL;
-      fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error));
-      grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
-    }
     gpr_atm_rel_store(&calld->subchannel_call,
                       (gpr_atm)(uintptr_t)subchannel_call);
-    retry_waiting_locked(exec_ctx, calld);
-    /* recurse to retry */
-    start_transport_stream_op_locked_inner(exec_ctx, op, elem);
+    if (error != GRPC_ERROR_NONE) {
+      fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error));
+      grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
+    } else {
+      retry_waiting_locked(exec_ctx, calld);
+      /* recurse to retry */
+      start_transport_stream_op_batch_locked_inner(exec_ctx, op, elem);
+    }
     /* early out */
     return;
   }
@@ -1174,15 +1189,16 @@
                    GRPC_ERROR_REF(error));
 }
 
-static void start_transport_stream_op_locked(grpc_exec_ctx *exec_ctx, void *arg,
-                                             grpc_error *error_ignored) {
-  GPR_TIMER_BEGIN("start_transport_stream_op_locked", 0);
+static void start_transport_stream_op_batch_locked(grpc_exec_ctx *exec_ctx,
+                                                   void *arg,
+                                                   grpc_error *error_ignored) {
+  GPR_TIMER_BEGIN("start_transport_stream_op_batch_locked", 0);
 
-  grpc_transport_stream_op *op = arg;
-  grpc_call_element *elem = op->handler_private.args[0];
+  grpc_transport_stream_op_batch *op = arg;
+  grpc_call_element *elem = op->handler_private.extra_arg;
   call_data *calld = elem->call_data;
 
-  if (op->recv_trailing_metadata != NULL) {
+  if (op->recv_trailing_metadata) {
     GPR_ASSERT(op->on_complete != NULL);
     calld->original_on_complete = op->on_complete;
     grpc_closure_init(&calld->on_complete, on_complete, elem,
@@ -1190,11 +1206,11 @@
     op->on_complete = &calld->on_complete;
   }
 
-  start_transport_stream_op_locked_inner(exec_ctx, op, elem);
+  start_transport_stream_op_batch_locked_inner(exec_ctx, op, elem);
 
   GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call,
-                        "start_transport_stream_op");
-  GPR_TIMER_END("start_transport_stream_op_locked", 0);
+                        "start_transport_stream_op_batch");
+  GPR_TIMER_END("start_transport_stream_op_batch_locked", 0);
 }
 
 /* The logic here is fairly complicated, due to (a) the fact that we
@@ -1205,39 +1221,40 @@
    We use double-checked locking to initially see if initialization has been
    performed. If it has not, we acquire the combiner and perform initialization.
    If it has, we proceed on the fast path. */
-static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                         grpc_call_element *elem,
-                                         grpc_transport_stream_op *op) {
+static void cc_start_transport_stream_op_batch(
+    grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+    grpc_transport_stream_op_batch *op) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  grpc_deadline_state_client_start_transport_stream_op(exec_ctx, elem, op);
+  grpc_deadline_state_client_start_transport_stream_op_batch(exec_ctx, elem,
+                                                             op);
   /* try to (atomically) get the call */
   grpc_subchannel_call *call = GET_CALL(calld);
-  GPR_TIMER_BEGIN("cc_start_transport_stream_op", 0);
+  GPR_TIMER_BEGIN("cc_start_transport_stream_op_batch", 0);
   if (call == CANCELLED_CALL) {
-    grpc_transport_stream_op_finish_with_failure(
+    grpc_transport_stream_op_batch_finish_with_failure(
         exec_ctx, op, GRPC_ERROR_REF(calld->cancel_error));
-    GPR_TIMER_END("cc_start_transport_stream_op", 0);
+    GPR_TIMER_END("cc_start_transport_stream_op_batch", 0);
     /* early out */
     return;
   }
   if (call != NULL) {
     grpc_subchannel_call_process_op(exec_ctx, call, op);
-    GPR_TIMER_END("cc_start_transport_stream_op", 0);
+    GPR_TIMER_END("cc_start_transport_stream_op_batch", 0);
     /* early out */
     return;
   }
   /* we failed; lock and figure out what to do */
-  GRPC_CALL_STACK_REF(calld->owning_call, "start_transport_stream_op");
-  op->handler_private.args[0] = elem;
+  GRPC_CALL_STACK_REF(calld->owning_call, "start_transport_stream_op_batch");
+  op->handler_private.extra_arg = elem;
   grpc_closure_sched(
       exec_ctx,
       grpc_closure_init(&op->handler_private.closure,
-                        start_transport_stream_op_locked, op,
+                        start_transport_stream_op_batch_locked, op,
                         grpc_combiner_scheduler(chand->combiner, false)),
       GRPC_ERROR_NONE);
-  GPR_TIMER_END("cc_start_transport_stream_op", 0);
+  GPR_TIMER_END("cc_start_transport_stream_op_batch", 0);
 }
 
 /* Constructor for call_data */
@@ -1296,7 +1313,7 @@
  */
 
 const grpc_channel_filter grpc_client_channel_filter = {
-    cc_start_transport_stream_op,
+    cc_start_transport_stream_op_batch,
     cc_start_transport_op,
     sizeof(call_data),
     cc_init_call_elem,
diff --git a/src/core/ext/client_channel/client_channel.h b/src/core/ext/filters/client_channel/client_channel.h
similarity index 88%
rename from src/core/ext/client_channel/client_channel.h
rename to src/core/ext/filters/client_channel/client_channel.h
index 5e6e64e..8d2490e 100644
--- a/src/core/ext/client_channel/client_channel.h
+++ b/src/core/ext/filters/client_channel/client_channel.h
@@ -31,11 +31,11 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H
 
-#include "src/core/ext/client_channel/client_channel_factory.h"
-#include "src/core/ext/client_channel/resolver.h"
+#include "src/core/ext/filters/client_channel/client_channel_factory.h"
+#include "src/core/ext/filters/client_channel/resolver.h"
 #include "src/core/lib/channel/channel_stack.h"
 
 // Channel arg key for server URI string.
@@ -61,4 +61,4 @@
 grpc_subchannel_call *grpc_client_channel_get_subchannel_call(
     grpc_call_element *elem);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H */
diff --git a/src/core/ext/client_channel/client_channel_factory.c b/src/core/ext/filters/client_channel/client_channel_factory.c
similarity index 97%
rename from src/core/ext/client_channel/client_channel_factory.c
rename to src/core/ext/filters/client_channel/client_channel_factory.c
index d2707a1..44e83b5 100644
--- a/src/core/ext/client_channel/client_channel_factory.c
+++ b/src/core/ext/filters/client_channel/client_channel_factory.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/client_channel_factory.h"
+#include "src/core/ext/filters/client_channel/client_channel_factory.h"
 
 void grpc_client_channel_factory_ref(grpc_client_channel_factory* factory) {
   factory->vtable->ref(factory);
diff --git a/src/core/ext/client_channel/client_channel_factory.h b/src/core/ext/filters/client_channel/client_channel_factory.h
similarity index 93%
rename from src/core/ext/client_channel/client_channel_factory.h
rename to src/core/ext/filters/client_channel/client_channel_factory.h
index bf2764b..2355588 100644
--- a/src/core/ext/client_channel/client_channel_factory.h
+++ b/src/core/ext/filters/client_channel/client_channel_factory.h
@@ -31,12 +31,12 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H
 
 #include <grpc/impl/codegen/grpc_types.h>
 
-#include "src/core/ext/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
 #include "src/core/lib/channel/channel_stack.h"
 
 // Channel arg key for client channel factory.
@@ -89,4 +89,4 @@
 grpc_arg grpc_client_channel_factory_create_channel_arg(
     grpc_client_channel_factory *factory);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H */
diff --git a/src/core/ext/client_channel/client_channel_plugin.c b/src/core/ext/filters/client_channel/client_channel_plugin.c
similarity index 87%
rename from src/core/ext/client_channel/client_channel_plugin.c
rename to src/core/ext/filters/client_channel/client_channel_plugin.c
index f51277d..944af01 100644
--- a/src/core/ext/client_channel/client_channel_plugin.c
+++ b/src/core/ext/filters/client_channel/client_channel_plugin.c
@@ -37,14 +37,14 @@
 
 #include <grpc/support/alloc.h>
 
-#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/client_channel/http_connect_handshaker.h"
-#include "src/core/ext/client_channel/http_proxy.h"
-#include "src/core/ext/client_channel/lb_policy_registry.h"
-#include "src/core/ext/client_channel/proxy_mapper_registry.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
-#include "src/core/ext/client_channel/retry_throttle.h"
-#include "src/core/ext/client_channel/subchannel_index.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
+#include "src/core/ext/filters/client_channel/http_proxy.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/retry_throttle.h"
+#include "src/core/ext/filters/client_channel/subchannel_index.h"
 #include "src/core/lib/surface/channel_init.h"
 
 static bool append_filter(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/ext/client_channel/connector.c b/src/core/ext/filters/client_channel/connector.c
similarity index 97%
rename from src/core/ext/client_channel/connector.c
rename to src/core/ext/filters/client_channel/connector.c
index 7a720fd..51c1d7e 100644
--- a/src/core/ext/client_channel/connector.c
+++ b/src/core/ext/filters/client_channel/connector.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/connector.h"
+#include "src/core/ext/filters/client_channel/connector.h"
 
 grpc_connector* grpc_connector_ref(grpc_connector* connector) {
   connector->vtable->ref(connector);
diff --git a/src/core/ext/client_channel/connector.h b/src/core/ext/filters/client_channel/connector.h
similarity index 95%
rename from src/core/ext/client_channel/connector.h
rename to src/core/ext/filters/client_channel/connector.h
index 94b5fb5..23040c3 100644
--- a/src/core/ext/client_channel/connector.h
+++ b/src/core/ext/filters/client_channel/connector.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_CONNECTOR_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_CONNECTOR_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTOR_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTOR_H
 
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -85,4 +85,4 @@
 void grpc_connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *connector,
                              grpc_error *why);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_CONNECTOR_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTOR_H */
diff --git a/src/core/ext/client_channel/http_connect_handshaker.c b/src/core/ext/filters/client_channel/http_connect_handshaker.c
similarity index 98%
rename from src/core/ext/client_channel/http_connect_handshaker.c
rename to src/core/ext/filters/client_channel/http_connect_handshaker.c
index 778d76c..c09a863 100644
--- a/src/core/ext/client_channel/http_connect_handshaker.c
+++ b/src/core/ext/filters/client_channel/http_connect_handshaker.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/http_connect_handshaker.h"
+#include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
 
 #include <string.h>
 
@@ -40,9 +40,9 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
-#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/handshaker_registry.h"
 #include "src/core/lib/http/format_request.h"
diff --git a/src/core/ext/client_channel/http_connect_handshaker.h b/src/core/ext/filters/client_channel/http_connect_handshaker.h
similarity index 90%
rename from src/core/ext/client_channel/http_connect_handshaker.h
rename to src/core/ext/filters/client_channel/http_connect_handshaker.h
index 3059d55..6d7c204 100644
--- a/src/core/ext/client_channel/http_connect_handshaker.h
+++ b/src/core/ext/filters/client_channel/http_connect_handshaker.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H
 
 /// Channel arg indicating the server in HTTP CONNECT request (string).
 /// The presence of this arg triggers the use of HTTP CONNECT.
@@ -46,4 +46,4 @@
 /// Registers handshaker factory.
 void grpc_http_connect_register_handshaker_factory();
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H */
diff --git a/src/core/ext/client_channel/http_proxy.c b/src/core/ext/filters/client_channel/http_proxy.c
similarity index 94%
rename from src/core/ext/client_channel/http_proxy.c
rename to src/core/ext/filters/client_channel/http_proxy.c
index e280cef..f8a2d06 100644
--- a/src/core/ext/client_channel/http_proxy.c
+++ b/src/core/ext/filters/client_channel/http_proxy.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/http_proxy.h"
+#include "src/core/ext/filters/client_channel/http_proxy.h"
 
 #include <stdbool.h>
 #include <string.h>
@@ -40,9 +40,9 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/http_connect_handshaker.h"
-#include "src/core/ext/client_channel/proxy_mapper_registry.h"
-#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
+#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/support/env.h"
 
diff --git a/src/core/ext/client_channel/http_proxy.h b/src/core/ext/filters/client_channel/http_proxy.h
similarity index 89%
rename from src/core/ext/client_channel/http_proxy.h
rename to src/core/ext/filters/client_channel/http_proxy.h
index c8882b1..f0df74b 100644
--- a/src/core/ext/client_channel/http_proxy.h
+++ b/src/core/ext/filters/client_channel/http_proxy.h
@@ -31,9 +31,9 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_PROXY_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_PROXY_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_PROXY_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_PROXY_H
 
 void grpc_register_http_proxy_mapper();
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_PROXY_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_PROXY_H */
diff --git a/src/core/ext/client_channel/lb_policy.c b/src/core/ext/filters/client_channel/lb_policy.c
similarity index 98%
rename from src/core/ext/client_channel/lb_policy.c
rename to src/core/ext/filters/client_channel/lb_policy.c
index aba51ad..2d31499 100644
--- a/src/core/ext/client_channel/lb_policy.c
+++ b/src/core/ext/filters/client_channel/lb_policy.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/lb_policy.h"
+#include "src/core/ext/filters/client_channel/lb_policy.h"
 #include "src/core/lib/iomgr/combiner.h"
 
 #define WEAK_REF_BITS 16
diff --git a/src/core/ext/client_channel/lb_policy.h b/src/core/ext/filters/client_channel/lb_policy.h
similarity index 97%
rename from src/core/ext/client_channel/lb_policy.h
rename to src/core/ext/filters/client_channel/lb_policy.h
index 3405709..2542766 100644
--- a/src/core/ext/client_channel/lb_policy.h
+++ b/src/core/ext/filters/client_channel/lb_policy.h
@@ -31,10 +31,10 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H
 
-#include "src/core/ext/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/transport/connectivity_state.h"
 
@@ -206,4 +206,4 @@
     grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
     grpc_error **connectivity_error);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H */
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
similarity index 98%
rename from src/core/ext/lb_policy/grpclb/grpclb.c
rename to src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
index 601b0e6..ff8d319 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb.c
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
@@ -106,14 +106,14 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 
-#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/client_channel/client_channel_factory.h"
-#include "src/core/ext/client_channel/lb_policy_factory.h"
-#include "src/core/ext/client_channel/lb_policy_registry.h"
-#include "src/core/ext/client_channel/parse_address.h"
-#include "src/core/ext/lb_policy/grpclb/grpclb.h"
-#include "src/core/ext/lb_policy/grpclb/grpclb_channel.h"
-#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel_factory.h"
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h"
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h"
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/sockaddr.h"
@@ -847,7 +847,9 @@
    * this is the right LB policy to use. */
   const grpc_arg *arg =
       grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
-  GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER);
+  if (arg == NULL || arg->type != GRPC_ARG_POINTER) {
+    return NULL;
+  }
   grpc_lb_addresses *addresses = arg->value.pointer.p;
   size_t num_grpclb_addrs = 0;
   for (size_t i = 0; i < addresses->num_addresses; ++i) {
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
similarity index 86%
rename from src/core/ext/lb_policy/grpclb/grpclb.h
rename to src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
index ff23f3a..b069fae 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
@@ -31,14 +31,14 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H
-#define GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H
 
-#include "src/core/ext/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 
 /** Returns a load balancing factory for the glb policy, which tries to connect
  * to a load balancing server to decide the next successfully connected
  * subchannel to pick. */
 grpc_lb_policy_factory *grpc_glb_lb_factory_create();
 
-#endif /* GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H */
diff --git a/src/core/ext/lb_policy/grpclb/grpclb_channel.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.c
similarity index 95%
rename from src/core/ext/lb_policy/grpclb/grpclb_channel.c
rename to src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.c
index 1b8bbab..d6201f2 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb_channel.c
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.c
@@ -34,8 +34,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/lb_policy/grpclb/grpclb_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/support/string.h"
diff --git a/src/core/ext/lb_policy/grpclb/grpclb_channel.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
similarity index 88%
rename from src/core/ext/lb_policy/grpclb/grpclb_channel.h
rename to src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
index f66082d..9730c97 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb_channel.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
@@ -31,10 +31,10 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H
-#define GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H
 
-#include "src/core/ext/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/lib/slice/slice_hash_table.h"
 
 /** Create the channel used for communicating with an LB service.
@@ -53,4 +53,5 @@
                                        grpc_slice_hash_table *targets_info,
                                        const grpc_channel_args *args);
 
-#endif /* GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H \
+          */
diff --git a/src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c
similarity index 96%
rename from src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c
rename to src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c
index 2fee5f1..a145cba 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c
@@ -34,8 +34,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/lb_policy/grpclb/grpclb_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/security/credentials/credentials.h"
diff --git a/src/core/ext/lb_policy/grpclb/load_balancer_api.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c
similarity index 98%
rename from src/core/ext/lb_policy/grpclb/load_balancer_api.c
rename to src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c
index 3c4604c..10af252 100644
--- a/src/core/ext/lb_policy/grpclb/load_balancer_api.c
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h"
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
 #include "third_party/nanopb/pb_decode.h"
 #include "third_party/nanopb/pb_encode.h"
 
diff --git a/src/core/ext/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
similarity index 89%
rename from src/core/ext/lb_policy/grpclb/load_balancer_api.h
rename to src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
index b4c967e..d014b88 100644
--- a/src/core/ext/lb_policy/grpclb/load_balancer_api.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
@@ -31,13 +31,13 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H
-#define GRPC_CORE_EXT_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H
 
 #include <grpc/slice_buffer.h>
 
-#include "src/core/ext/client_channel/lb_policy_factory.h"
-#include "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -101,4 +101,5 @@
 }
 #endif
 
-#endif /* GRPC_CORE_EXT_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H \
+          */
diff --git a/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
similarity index 97%
rename from src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
rename to src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
index e352e03..e9adf98 100644
--- a/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
@@ -1,7 +1,7 @@
 /* Automatically generated nanopb constant definitions */
 /* Generated by nanopb-0.3.7-dev */
 
-#include "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
 
 /* @@protoc_insertion_point(includes) */
 #if PB_PROTO_HEADER_VERSION != 30
diff --git a/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
similarity index 100%
rename from src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
rename to src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
diff --git a/src/core/ext/lb_policy/pick_first/pick_first.c b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c
similarity index 98%
rename from src/core/ext/lb_policy/pick_first/pick_first.c
rename to src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c
index fc65dfd..2b77cd3 100644
--- a/src/core/ext/lb_policy/pick_first/pick_first.c
+++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c
@@ -35,8 +35,8 @@
 
 #include <grpc/support/alloc.h>
 
-#include "src/core/ext/client_channel/lb_policy_registry.h"
-#include "src/core/ext/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
@@ -402,7 +402,9 @@
    * addresses, since we don't know how to handle them. */
   const grpc_arg *arg =
       grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
-  GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER);
+  if (arg == NULL || arg->type != GRPC_ARG_POINTER) {
+    return NULL;
+  }
   grpc_lb_addresses *addresses = arg->value.pointer.p;
   size_t num_addrs = 0;
   for (size_t i = 0; i < addresses->num_addresses; i++) {
diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c
similarity index 98%
rename from src/core/ext/lb_policy/round_robin/round_robin.c
rename to src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c
index a62082a..ff41e61 100644
--- a/src/core/ext/lb_policy/round_robin/round_robin.c
+++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c
@@ -63,8 +63,8 @@
 
 #include <grpc/support/alloc.h>
 
-#include "src/core/ext/client_channel/lb_policy_registry.h"
-#include "src/core/ext/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/combiner.h"
@@ -691,7 +691,9 @@
    * addresses, since we don't know how to handle them. */
   const grpc_arg *arg =
       grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
-  GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER);
+  if (arg == NULL || arg->type != GRPC_ARG_POINTER) {
+    return NULL;
+  }
   grpc_lb_addresses *addresses = arg->value.pointer.p;
   size_t num_addrs = 0;
   for (size_t i = 0; i < addresses->num_addresses; i++) {
diff --git a/src/core/ext/client_channel/lb_policy_factory.c b/src/core/ext/filters/client_channel/lb_policy_factory.c
similarity index 98%
rename from src/core/ext/client_channel/lb_policy_factory.c
rename to src/core/ext/filters/client_channel/lb_policy_factory.c
index 7af9bb0..e2af216 100644
--- a/src/core/ext/client_channel/lb_policy_factory.c
+++ b/src/core/ext/filters/client_channel/lb_policy_factory.c
@@ -36,7 +36,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 
 grpc_lb_addresses* grpc_lb_addresses_create(
     size_t num_addresses, const grpc_lb_user_data_vtable* user_data_vtable) {
diff --git a/src/core/ext/client_channel/lb_policy_factory.h b/src/core/ext/filters/client_channel/lb_policy_factory.h
similarity index 93%
rename from src/core/ext/client_channel/lb_policy_factory.h
rename to src/core/ext/filters/client_channel/lb_policy_factory.h
index 27c12c0..81ab12e 100644
--- a/src/core/ext/client_channel/lb_policy_factory.h
+++ b/src/core/ext/filters/client_channel/lb_policy_factory.h
@@ -31,11 +31,11 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_FACTORY_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_FACTORY_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H
 
-#include "src/core/ext/client_channel/client_channel_factory.h"
-#include "src/core/ext/client_channel/lb_policy.h"
+#include "src/core/ext/filters/client_channel/client_channel_factory.h"
+#include "src/core/ext/filters/client_channel/lb_policy.h"
 
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -131,4 +131,4 @@
     grpc_exec_ctx *exec_ctx, grpc_lb_policy_factory *factory,
     grpc_lb_policy_args *args);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_FACTORY_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H */
diff --git a/src/core/ext/client_channel/lb_policy_registry.c b/src/core/ext/filters/client_channel/lb_policy_registry.c
similarity index 97%
rename from src/core/ext/client_channel/lb_policy_registry.c
rename to src/core/ext/filters/client_channel/lb_policy_registry.c
index 90c149d..1376673 100644
--- a/src/core/ext/client_channel/lb_policy_registry.c
+++ b/src/core/ext/filters/client_channel/lb_policy_registry.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 
 #include <string.h>
 
diff --git a/src/core/ext/client_channel/lb_policy_registry.h b/src/core/ext/filters/client_channel/lb_policy_registry.h
similarity index 88%
rename from src/core/ext/client_channel/lb_policy_registry.h
rename to src/core/ext/filters/client_channel/lb_policy_registry.h
index 21c468e..dfdec13 100644
--- a/src/core/ext/client_channel/lb_policy_registry.h
+++ b/src/core/ext/filters/client_channel/lb_policy_registry.h
@@ -31,10 +31,10 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H
 
-#include "src/core/ext/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
 /** Initialize the registry and set \a default_factory as the factory to be
@@ -52,4 +52,4 @@
 grpc_lb_policy *grpc_lb_policy_create(grpc_exec_ctx *exec_ctx, const char *name,
                                       grpc_lb_policy_args *args);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H */
diff --git a/src/core/ext/client_channel/parse_address.c b/src/core/ext/filters/client_channel/parse_address.c
similarity index 98%
rename from src/core/ext/client_channel/parse_address.c
rename to src/core/ext/filters/client_channel/parse_address.c
index cd1b2cd..0c97062 100644
--- a/src/core/ext/client_channel/parse_address.c
+++ b/src/core/ext/filters/client_channel/parse_address.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/parse_address.h"
+#include "src/core/ext/filters/client_channel/parse_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 
 #include <stdio.h>
diff --git a/src/core/ext/client_channel/parse_address.h b/src/core/ext/filters/client_channel/parse_address.h
similarity index 89%
rename from src/core/ext/client_channel/parse_address.h
rename to src/core/ext/filters/client_channel/parse_address.h
index bf99c52..c8d77ba 100644
--- a/src/core/ext/client_channel/parse_address.h
+++ b/src/core/ext/filters/client_channel/parse_address.h
@@ -31,12 +31,12 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_PARSE_ADDRESS_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_PARSE_ADDRESS_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H
 
 #include <stddef.h>
 
-#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
 /** Populate \a addr and \a len from \a uri, whose path is expected to contain a
@@ -51,4 +51,4 @@
  * host:port pair. Returns true upon success. */
 int parse_ipv6(grpc_uri *uri, grpc_resolved_address *resolved_addr);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_PARSE_ADDRESS_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H */
diff --git a/src/core/ext/client_channel/proxy_mapper.c b/src/core/ext/filters/client_channel/proxy_mapper.c
similarity index 97%
rename from src/core/ext/client_channel/proxy_mapper.c
rename to src/core/ext/filters/client_channel/proxy_mapper.c
index f92afe8..6dddd3c 100644
--- a/src/core/ext/client_channel/proxy_mapper.c
+++ b/src/core/ext/filters/client_channel/proxy_mapper.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/proxy_mapper.h"
+#include "src/core/ext/filters/client_channel/proxy_mapper.h"
 
 void grpc_proxy_mapper_init(const grpc_proxy_mapper_vtable* vtable,
                             grpc_proxy_mapper* mapper) {
diff --git a/src/core/ext/client_channel/proxy_mapper.h b/src/core/ext/filters/client_channel/proxy_mapper.h
similarity index 95%
rename from src/core/ext/client_channel/proxy_mapper.h
rename to src/core/ext/filters/client_channel/proxy_mapper.h
index 6e4607f..d0c47d3 100644
--- a/src/core/ext/client_channel/proxy_mapper.h
+++ b/src/core/ext/filters/client_channel/proxy_mapper.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_H
 
 #include <stdbool.h>
 
@@ -86,4 +86,4 @@
 
 void grpc_proxy_mapper_destroy(grpc_proxy_mapper* mapper);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_H */
diff --git a/src/core/ext/client_channel/proxy_mapper_registry.c b/src/core/ext/filters/client_channel/proxy_mapper_registry.c
similarity index 98%
rename from src/core/ext/client_channel/proxy_mapper_registry.c
rename to src/core/ext/filters/client_channel/proxy_mapper_registry.c
index 0935ddb..7a39289 100644
--- a/src/core/ext/client_channel/proxy_mapper_registry.c
+++ b/src/core/ext/filters/client_channel/proxy_mapper_registry.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/proxy_mapper_registry.h"
+#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
 
 #include <string.h>
 
diff --git a/src/core/ext/client_channel/proxy_mapper_registry.h b/src/core/ext/filters/client_channel/proxy_mapper_registry.h
similarity index 90%
rename from src/core/ext/client_channel/proxy_mapper_registry.h
rename to src/core/ext/filters/client_channel/proxy_mapper_registry.h
index 742b57a..8b5686d 100644
--- a/src/core/ext/client_channel/proxy_mapper_registry.h
+++ b/src/core/ext/filters/client_channel/proxy_mapper_registry.h
@@ -31,10 +31,10 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H
 
-#include "src/core/ext/client_channel/proxy_mapper.h"
+#include "src/core/ext/filters/client_channel/proxy_mapper.h"
 
 void grpc_proxy_mapper_registry_init();
 void grpc_proxy_mapper_registry_shutdown();
@@ -56,4 +56,4 @@
                                     grpc_resolved_address** new_address,
                                     grpc_channel_args** new_args);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H */
diff --git a/src/core/ext/client_channel/resolver.c b/src/core/ext/filters/client_channel/resolver.c
similarity index 98%
rename from src/core/ext/client_channel/resolver.c
rename to src/core/ext/filters/client_channel/resolver.c
index b1a1faa..cafa283 100644
--- a/src/core/ext/client_channel/resolver.c
+++ b/src/core/ext/filters/client_channel/resolver.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/resolver.h"
+#include "src/core/ext/filters/client_channel/resolver.h"
 #include "src/core/lib/iomgr/combiner.h"
 
 void grpc_resolver_init(grpc_resolver *resolver,
diff --git a/src/core/ext/client_channel/resolver.h b/src/core/ext/filters/client_channel/resolver.h
similarity index 94%
rename from src/core/ext/client_channel/resolver.h
rename to src/core/ext/filters/client_channel/resolver.h
index bbba424..55f9124 100644
--- a/src/core/ext/client_channel/resolver.h
+++ b/src/core/ext/filters/client_channel/resolver.h
@@ -31,10 +31,10 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H
 
-#include "src/core/ext/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
 #include "src/core/lib/iomgr/iomgr.h"
 
 typedef struct grpc_resolver grpc_resolver;
@@ -98,4 +98,4 @@
                                grpc_channel_args **result,
                                grpc_closure *on_complete);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H */
diff --git a/src/core/ext/resolver/README.md b/src/core/ext/filters/client_channel/resolver/README.md
similarity index 100%
rename from src/core/ext/resolver/README.md
rename to src/core/ext/filters/client_channel/resolver/README.md
diff --git a/src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
similarity index 97%
rename from src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c
rename to src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
index f27da23..ffaeeed 100644
--- a/src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
@@ -40,10 +40,10 @@
 #include <grpc/support/host_port.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/http_connect_handshaker.h"
-#include "src/core/ext/client_channel/lb_policy_registry.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
-#include "src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h"
+#include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/resolve_address.h"
diff --git a/src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
similarity index 90%
rename from src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h
rename to src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
index 334feaa..aa88940 100644
--- a/src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H
-#define GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H
 
 #include <ares.h>
 
@@ -62,4 +62,5 @@
    of ARES_ECANCELLED. */
 void grpc_ares_ev_driver_destroy(grpc_ares_ev_driver *ev_driver);
 
-#endif /* GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H \
+          */
diff --git a/src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
similarity index 98%
rename from src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
rename to src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
index fab4f0c..1e4f3eb 100644
--- a/src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
@@ -34,14 +34,14 @@
 #include "src/core/lib/iomgr/port.h"
 #if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET)
 
-#include "src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h"
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h"
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
diff --git a/src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
similarity index 98%
rename from src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c
rename to src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
index 3eee8e3..09c46a6 100644
--- a/src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
@@ -34,7 +34,7 @@
 #include <grpc/support/port_platform.h>
 #if GRPC_ARES == 1 && !defined(GRPC_UV)
 
-#include "src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h"
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 
@@ -48,7 +48,7 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h"
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
diff --git a/src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
similarity index 91%
rename from src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h
rename to src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
index ab00a26..3dd40ea 100644
--- a/src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H
-#define GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H
 
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/iomgr.h"
@@ -60,4 +60,5 @@
    it has been called the same number of times as grpc_ares_init(). */
 void grpc_ares_cleanup(void);
 
-#endif /* GRPC_CORE_EXT_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \
+          */
diff --git a/src/core/ext/resolver/dns/native/README.md b/src/core/ext/filters/client_channel/resolver/dns/native/README.md
similarity index 100%
rename from src/core/ext/resolver/dns/native/README.md
rename to src/core/ext/filters/client_channel/resolver/dns/native/README.md
diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c
similarity index 98%
rename from src/core/ext/resolver/dns/native/dns_resolver.c
rename to src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c
index 97cd048..ebe6a07 100644
--- a/src/core/ext/resolver/dns/native/dns_resolver.c
+++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c
@@ -37,8 +37,8 @@
 #include <grpc/support/host_port.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/lb_policy_registry.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/resolve_address.h"
diff --git a/src/core/ext/resolver/sockaddr/README.md b/src/core/ext/filters/client_channel/resolver/sockaddr/README.md
similarity index 100%
rename from src/core/ext/resolver/sockaddr/README.md
rename to src/core/ext/filters/client_channel/resolver/sockaddr/README.md
diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c
similarity index 97%
rename from src/core/ext/resolver/sockaddr/sockaddr_resolver.c
rename to src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c
index da5923d..54f020d 100644
--- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
+++ b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c
@@ -41,9 +41,9 @@
 #include <grpc/support/port_platform.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/lb_policy_factory.h"
-#include "src/core/ext/client_channel/parse_address.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/parse_address.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/resolve_address.h"
diff --git a/src/core/ext/client_channel/resolver_factory.c b/src/core/ext/filters/client_channel/resolver_factory.c
similarity index 96%
rename from src/core/ext/client_channel/resolver_factory.c
rename to src/core/ext/filters/client_channel/resolver_factory.c
index 00bbb92..07f9e4c 100644
--- a/src/core/ext/client_channel/resolver_factory.c
+++ b/src/core/ext/filters/client_channel/resolver_factory.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/resolver_factory.h"
+#include "src/core/ext/filters/client_channel/resolver_factory.h"
 
 void grpc_resolver_factory_ref(grpc_resolver_factory* factory) {
   factory->vtable->ref(factory);
diff --git a/src/core/ext/client_channel/resolver_factory.h b/src/core/ext/filters/client_channel/resolver_factory.h
similarity index 88%
rename from src/core/ext/client_channel/resolver_factory.h
rename to src/core/ext/filters/client_channel/resolver_factory.h
index e3cd99e..f2fcfc0 100644
--- a/src/core/ext/client_channel/resolver_factory.h
+++ b/src/core/ext/filters/client_channel/resolver_factory.h
@@ -31,12 +31,12 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_FACTORY_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_FACTORY_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H
 
-#include "src/core/ext/client_channel/client_channel_factory.h"
-#include "src/core/ext/client_channel/resolver.h"
-#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/ext/filters/client_channel/client_channel_factory.h"
+#include "src/core/ext/filters/client_channel/resolver.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 
 typedef struct grpc_resolver_factory grpc_resolver_factory;
@@ -82,4 +82,4 @@
 char *grpc_resolver_factory_get_default_authority(
     grpc_resolver_factory *factory, grpc_uri *uri);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_FACTORY_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H */
diff --git a/src/core/ext/client_channel/resolver_registry.c b/src/core/ext/filters/client_channel/resolver_registry.c
similarity index 98%
rename from src/core/ext/client_channel/resolver_registry.c
rename to src/core/ext/filters/client_channel/resolver_registry.c
index 0f074a3..fa997bd 100644
--- a/src/core/ext/client_channel/resolver_registry.c
+++ b/src/core/ext/filters/client_channel/resolver_registry.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
 
 #include <string.h>
 
diff --git a/src/core/ext/client_channel/resolver_registry.h b/src/core/ext/filters/client_channel/resolver_registry.h
similarity index 93%
rename from src/core/ext/client_channel/resolver_registry.h
rename to src/core/ext/filters/client_channel/resolver_registry.h
index 1a3ebee..f2e9f92 100644
--- a/src/core/ext/client_channel/resolver_registry.h
+++ b/src/core/ext/filters/client_channel/resolver_registry.h
@@ -31,10 +31,10 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_REGISTRY_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_REGISTRY_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H
 
-#include "src/core/ext/client_channel/resolver_factory.h"
+#include "src/core/ext/filters/client_channel/resolver_factory.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 
 void grpc_resolver_registry_init();
@@ -81,4 +81,4 @@
 char *grpc_resolver_factory_add_default_prefix_if_needed(
     grpc_exec_ctx *exec_ctx, const char *target);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_REGISTRY_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H */
diff --git a/src/core/ext/client_channel/retry_throttle.c b/src/core/ext/filters/client_channel/retry_throttle.c
similarity index 98%
rename from src/core/ext/client_channel/retry_throttle.c
rename to src/core/ext/filters/client_channel/retry_throttle.c
index 8926c3d..dd78a17 100644
--- a/src/core/ext/client_channel/retry_throttle.c
+++ b/src/core/ext/filters/client_channel/retry_throttle.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/retry_throttle.h"
+#include "src/core/ext/filters/client_channel/retry_throttle.h"
 
 #include <limits.h>
 #include <string.h>
diff --git a/src/core/ext/client_channel/retry_throttle.h b/src/core/ext/filters/client_channel/retry_throttle.h
similarity index 93%
rename from src/core/ext/client_channel/retry_throttle.h
rename to src/core/ext/filters/client_channel/retry_throttle.h
index f9971fa..640865c 100644
--- a/src/core/ext/client_channel/retry_throttle.h
+++ b/src/core/ext/filters/client_channel/retry_throttle.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_RETRY_THROTTLE_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_RETRY_THROTTLE_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_THROTTLE_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_THROTTLE_H
 
 #include <stdbool.h>
 
@@ -62,4 +62,4 @@
 grpc_server_retry_throttle_data* grpc_retry_throttle_map_get_data_for_server(
     const char* server_name, int max_milli_tokens, int milli_token_ratio);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_RETRY_THROTTLE_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_THROTTLE_H */
diff --git a/src/core/ext/client_channel/subchannel.c b/src/core/ext/filters/client_channel/subchannel.c
similarity index 97%
rename from src/core/ext/client_channel/subchannel.c
rename to src/core/ext/filters/client_channel/subchannel.c
index 063c0ba..9a7a7a0 100644
--- a/src/core/ext/client_channel/subchannel.c
+++ b/src/core/ext/filters/client_channel/subchannel.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
 
 #include <limits.h>
 #include <string.h>
@@ -40,11 +40,11 @@
 #include <grpc/support/avl.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/client_channel/parse_address.h"
-#include "src/core/ext/client_channel/proxy_mapper_registry.h"
-#include "src/core/ext/client_channel/subchannel_index.h"
-#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/parse_address.h"
+#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
+#include "src/core/ext/filters/client_channel/subchannel_index.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
@@ -360,7 +360,6 @@
     for (size_t i = 0; i < c->args->num_args; i++) {
       if (0 == strcmp(c->args->args[i].key,
                       "grpc.testing.fixed_reconnect_backoff_ms")) {
-        GPR_ASSERT(c->args->args[i].type == GRPC_ARG_INTEGER);
         fixed_reconnect_backoff = true;
         initial_backoff_ms = min_backoff_ms = max_backoff_ms =
             grpc_channel_arg_get_integer(
@@ -749,11 +748,11 @@
 
 void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
                                      grpc_subchannel_call *call,
-                                     grpc_transport_stream_op *op) {
+                                     grpc_transport_stream_op_batch *op) {
   GPR_TIMER_BEGIN("grpc_subchannel_call_process_op", 0);
   grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call);
   grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0);
-  top_elem->filter->start_transport_stream_op(exec_ctx, top_elem, op);
+  top_elem->filter->start_transport_stream_op_batch(exec_ctx, top_elem, op);
   GPR_TIMER_END("grpc_subchannel_call_process_op", 0);
 }
 
@@ -770,7 +769,7 @@
   *call = gpr_arena_alloc(
       args->arena, sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
   grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
-  (*call)->connection = con;  // Ref is added below.
+  (*call)->connection = GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
   const grpc_call_element_args call_args = {.call_stack = callstk,
                                             .server_transport_data = NULL,
                                             .context = NULL,
@@ -783,11 +782,8 @@
   if (error != GRPC_ERROR_NONE) {
     const char *error_string = grpc_error_string(error);
     gpr_log(GPR_ERROR, "error: %s", error_string);
-
-    gpr_free(*call);
     return error;
   }
-  GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
   grpc_call_stack_set_pollset_or_pollset_set(exec_ctx, callstk, args->pollent);
   return GRPC_ERROR_NONE;
 }
diff --git a/src/core/ext/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h
similarity index 96%
rename from src/core/ext/client_channel/subchannel.h
rename to src/core/ext/filters/client_channel/subchannel.h
index 3e64a25..6473de4 100644
--- a/src/core/ext/client_channel/subchannel.h
+++ b/src/core/ext/filters/client_channel/subchannel.h
@@ -31,10 +31,10 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_H
 
-#include "src/core/ext/client_channel/connector.h"
+#include "src/core/ext/filters/client_channel/connector.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/support/arena.h"
@@ -157,7 +157,7 @@
 /** continue processing a transport op */
 void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
                                      grpc_subchannel_call *subchannel_call,
-                                     grpc_transport_stream_op *op);
+                                     grpc_transport_stream_op_batch *op);
 
 /** continue querying for peer */
 char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx,
@@ -200,4 +200,4 @@
 /// Caller is responsible for freeing the string.
 grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address *addr);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_H */
diff --git a/src/core/ext/client_channel/subchannel_index.c b/src/core/ext/filters/client_channel/subchannel_index.c
similarity index 98%
rename from src/core/ext/client_channel/subchannel_index.c
rename to src/core/ext/filters/client_channel/subchannel_index.c
index 1188930..f6ef4a8 100644
--- a/src/core/ext/client_channel/subchannel_index.c
+++ b/src/core/ext/filters/client_channel/subchannel_index.c
@@ -31,7 +31,7 @@
 //
 //
 
-#include "src/core/ext/client_channel/subchannel_index.h"
+#include "src/core/ext/filters/client_channel/subchannel_index.h"
 
 #include <stdbool.h>
 #include <string.h>
diff --git a/src/core/ext/client_channel/subchannel_index.h b/src/core/ext/filters/client_channel/subchannel_index.h
similarity index 90%
rename from src/core/ext/client_channel/subchannel_index.h
rename to src/core/ext/filters/client_channel/subchannel_index.h
index a67bd5e..f673ade 100644
--- a/src/core/ext/client_channel/subchannel_index.h
+++ b/src/core/ext/filters/client_channel/subchannel_index.h
@@ -31,11 +31,11 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H
 
-#include "src/core/ext/client_channel/connector.h"
-#include "src/core/ext/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/connector.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
 
 /** \file Provides an index of active subchannels so that they can be
     shared amongst channels */
@@ -74,4 +74,4 @@
 /** Shutdown the subchannel index (global) */
 void grpc_subchannel_index_shutdown(void);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H */
diff --git a/src/core/ext/client_channel/uri_parser.c b/src/core/ext/filters/client_channel/uri_parser.c
similarity index 99%
rename from src/core/ext/client_channel/uri_parser.c
rename to src/core/ext/filters/client_channel/uri_parser.c
index d385db0..01b9991 100644
--- a/src/core/ext/client_channel/uri_parser.c
+++ b/src/core/ext/filters/client_channel/uri_parser.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
 
 #include <string.h>
 
diff --git a/src/core/ext/client_channel/uri_parser.h b/src/core/ext/filters/client_channel/uri_parser.h
similarity index 92%
rename from src/core/ext/client_channel/uri_parser.h
rename to src/core/ext/filters/client_channel/uri_parser.h
index efd4302..2698d44 100644
--- a/src/core/ext/client_channel/uri_parser.h
+++ b/src/core/ext/filters/client_channel/uri_parser.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_URI_PARSER_H
-#define GRPC_CORE_EXT_CLIENT_CHANNEL_URI_PARSER_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H
 
 #include <stddef.h>
 #include "src/core/lib/iomgr/exec_ctx.h"
@@ -62,4 +62,4 @@
 /** destroy a uri */
 void grpc_uri_destroy(grpc_uri *uri);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_URI_PARSER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H */
diff --git a/src/core/ext/load_reporting/load_reporting.c b/src/core/ext/filters/load_reporting/load_reporting.c
similarity index 96%
rename from src/core/ext/load_reporting/load_reporting.c
rename to src/core/ext/filters/load_reporting/load_reporting.c
index 942aea4..9fb33ba 100644
--- a/src/core/ext/load_reporting/load_reporting.c
+++ b/src/core/ext/filters/load_reporting/load_reporting.c
@@ -38,8 +38,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/ext/load_reporting/load_reporting.h"
-#include "src/core/ext/load_reporting/load_reporting_filter.h"
+#include "src/core/ext/filters/load_reporting/load_reporting.h"
+#include "src/core/ext/filters/load_reporting/load_reporting_filter.h"
 #include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/call.h"
diff --git a/src/core/ext/load_reporting/load_reporting.h b/src/core/ext/filters/load_reporting/load_reporting.h
similarity index 93%
rename from src/core/ext/load_reporting/load_reporting.h
rename to src/core/ext/filters/load_reporting/load_reporting.h
index 22859a5..e05a9dc 100644
--- a/src/core/ext/load_reporting/load_reporting.h
+++ b/src/core/ext/filters/load_reporting/load_reporting.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_H
-#define GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_H
+#ifndef GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_H
+#define GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_H
 
 #include <grpc/impl/codegen/grpc_types.h>
 
@@ -70,4 +70,4 @@
 /** Return a \a grpc_arg enabling load reporting */
 grpc_arg grpc_load_reporting_enable_arg();
 
-#endif /* GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_H */
+#endif /* GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_H */
diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/filters/load_reporting/load_reporting_filter.c
similarity index 90%
rename from src/core/ext/load_reporting/load_reporting_filter.c
rename to src/core/ext/filters/load_reporting/load_reporting_filter.c
index ea57c85..57b25d0 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.c
+++ b/src/core/ext/filters/load_reporting/load_reporting_filter.c
@@ -39,8 +39,8 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/ext/load_reporting/load_reporting.h"
-#include "src/core/ext/load_reporting/load_reporting_filter.h"
+#include "src/core/ext/filters/load_reporting/load_reporting.h"
+#include "src/core/ext/filters/load_reporting/load_reporting_filter.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
@@ -183,25 +183,28 @@
   */
 }
 
-static void lr_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                         grpc_call_element *elem,
-                                         grpc_transport_stream_op *op) {
-  GPR_TIMER_BEGIN("lr_start_transport_stream_op", 0);
+static void lr_start_transport_stream_op_batch(
+    grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+    grpc_transport_stream_op_batch *op) {
+  GPR_TIMER_BEGIN("lr_start_transport_stream_op_batch", 0);
   call_data *calld = elem->call_data;
 
   if (op->recv_initial_metadata) {
-    calld->recv_initial_metadata = op->recv_initial_metadata;
+    calld->recv_initial_metadata =
+        op->payload->recv_initial_metadata.recv_initial_metadata;
     /* substitute our callback for the higher callback */
-    calld->ops_recv_initial_metadata_ready = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = &calld->on_initial_md_ready;
+    calld->ops_recv_initial_metadata_ready =
+        op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+    op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+        &calld->on_initial_md_ready;
   }
   grpc_call_next_op(exec_ctx, elem, op);
 
-  GPR_TIMER_END("lr_start_transport_stream_op", 0);
+  GPR_TIMER_END("lr_start_transport_stream_op_batch", 0);
 }
 
 const grpc_channel_filter grpc_load_reporting_filter = {
-    lr_start_transport_stream_op,
+    lr_start_transport_stream_op_batch,
     grpc_channel_next_op,
     sizeof(call_data),
     init_call_elem,
diff --git a/src/core/ext/load_reporting/load_reporting_filter.h b/src/core/ext/filters/load_reporting/load_reporting_filter.h
similarity index 85%
rename from src/core/ext/load_reporting/load_reporting_filter.h
rename to src/core/ext/filters/load_reporting/load_reporting_filter.h
index 160ed32..da884a1 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.h
+++ b/src/core/ext/filters/load_reporting/load_reporting_filter.h
@@ -31,12 +31,12 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_FILTER_H
-#define GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_FILTER_H
+#ifndef GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_FILTER_H
+#define GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_FILTER_H
 
-#include "src/core/ext/load_reporting/load_reporting.h"
+#include "src/core/ext/filters/load_reporting/load_reporting.h"
 #include "src/core/lib/channel/channel_stack.h"
 
 extern const grpc_channel_filter grpc_load_reporting_filter;
 
-#endif /* GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_FILTER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_LOAD_REPORTING_FILTER_H */
diff --git a/src/core/lib/channel/max_age_filter.c b/src/core/ext/filters/max_age/max_age_filter.c
similarity index 87%
rename from src/core/lib/channel/max_age_filter.c
rename to src/core/ext/filters/max_age/max_age_filter.c
index c254814..a045f0a 100644
--- a/src/core/lib/channel/max_age_filter.c
+++ b/src/core/ext/filters/max_age/max_age_filter.c
@@ -31,19 +31,21 @@
  *
  */
 
-#include "src/core/lib/channel/message_size_filter.h"
+#include "src/core/ext/filters/max_age/max_age_filter.h"
 
 #include <limits.h>
 #include <string.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/surface/channel_init.h"
 #include "src/core/lib/transport/http2_errors.h"
-#include "src/core/lib/transport/service_config.h"
 
 #define DEFAULT_MAX_CONNECTION_AGE_MS INT_MAX
 #define DEFAULT_MAX_CONNECTION_AGE_GRACE_MS INT_MAX
 #define DEFAULT_MAX_CONNECTION_IDLE_MS INT_MAX
+#define MAX_CONNECTION_AGE_JITTER 0.1
 
 typedef struct channel_data {
   /* We take a reference to the channel stack for the timer callback */
@@ -252,6 +254,21 @@
   }
 }
 
+/* A random jitter of +/-10% will be added to MAX_CONNECTION_AGE to spread out
+   connection storms. Note that the MAX_CONNECTION_AGE option without jitter
+   would not create connection storms by itself, but if there happened to be a
+   connection storm it could cause it to repeat at a fixed period. */
+static int add_random_max_connection_age_jitter(int value) {
+  /* generate a random number between 1 - MAX_CONNECTION_AGE_JITTER and
+     1 + MAX_CONNECTION_AGE_JITTER */
+  double multiplier = rand() * MAX_CONNECTION_AGE_JITTER * 2.0 / RAND_MAX +
+                      1.0 - MAX_CONNECTION_AGE_JITTER;
+  double result = multiplier * value;
+  /* INT_MAX - 0.5 converts the value to float, so that result will not be
+     cast to int implicitly before the comparison. */
+  return result > INT_MAX - 0.5 ? INT_MAX : (int)result;
+}
+
 /* Constructor for call_data. */
 static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
                                   grpc_call_element* elem,
@@ -281,7 +298,9 @@
   chand->max_connection_age =
       DEFAULT_MAX_CONNECTION_AGE_MS == INT_MAX
           ? gpr_inf_future(GPR_TIMESPAN)
-          : gpr_time_from_millis(DEFAULT_MAX_CONNECTION_AGE_MS, GPR_TIMESPAN);
+          : gpr_time_from_millis(add_random_max_connection_age_jitter(
+                                     DEFAULT_MAX_CONNECTION_AGE_MS),
+                                 GPR_TIMESPAN);
   chand->max_connection_age_grace =
       DEFAULT_MAX_CONNECTION_AGE_GRACE_MS == INT_MAX
           ? gpr_inf_future(GPR_TIMESPAN)
@@ -298,8 +317,10 @@
           &args->channel_args->args[i],
           (grpc_integer_options){DEFAULT_MAX_CONNECTION_AGE_MS, 1, INT_MAX});
       chand->max_connection_age =
-          value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN)
-                           : gpr_time_from_millis(value, GPR_TIMESPAN);
+          value == INT_MAX
+              ? gpr_inf_future(GPR_TIMESPAN)
+              : gpr_time_from_millis(
+                    add_random_max_connection_age_jitter(value), GPR_TIMESPAN);
     } else if (0 == strcmp(args->channel_args->args[i].key,
                            GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS)) {
       const int value = grpc_channel_arg_get_integer(
@@ -384,3 +405,34 @@
     grpc_call_next_get_peer,
     grpc_channel_next_get_info,
     "max_age"};
+
+static bool maybe_add_max_age_filter(grpc_exec_ctx* exec_ctx,
+                                     grpc_channel_stack_builder* builder,
+                                     void* arg) {
+  const grpc_channel_args* channel_args =
+      grpc_channel_stack_builder_get_channel_arguments(builder);
+  const grpc_arg* a =
+      grpc_channel_args_find(channel_args, GRPC_ARG_MAX_CONNECTION_AGE_MS);
+  bool enable = false;
+  if (a != NULL && a->type == GRPC_ARG_INTEGER && a->value.integer != INT_MAX) {
+    enable = true;
+  }
+  a = grpc_channel_args_find(channel_args, GRPC_ARG_MAX_CONNECTION_IDLE_MS);
+  if (a != NULL && a->type == GRPC_ARG_INTEGER && a->value.integer != INT_MAX) {
+    enable = true;
+  }
+  if (enable) {
+    return grpc_channel_stack_builder_prepend_filter(
+        builder, &grpc_max_age_filter, NULL, NULL);
+  } else {
+    return true;
+  }
+}
+
+void grpc_max_age_filter_init(void) {
+  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
+                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+                                   maybe_add_max_age_filter, NULL);
+}
+
+void grpc_max_age_filter_shutdown(void) {}
diff --git a/src/core/lib/channel/max_age_filter.h b/src/core/ext/filters/max_age/max_age_filter.h
similarity index 90%
rename from src/core/lib/channel/max_age_filter.h
rename to src/core/ext/filters/max_age/max_age_filter.h
index 93e357a..ed20152 100644
--- a/src/core/lib/channel/max_age_filter.h
+++ b/src/core/ext/filters/max_age/max_age_filter.h
@@ -29,11 +29,11 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //
 
-#ifndef GRPC_CORE_LIB_CHANNEL_MAX_AGE_FILTER_H
-#define GRPC_CORE_LIB_CHANNEL_MAX_AGE_FILTER_H
+#ifndef GRPC_CORE_EXT_FILTERS_MAX_AGE_MAX_AGE_FILTER_H
+#define GRPC_CORE_EXT_FILTERS_MAX_AGE_MAX_AGE_FILTER_H
 
 #include "src/core/lib/channel/channel_stack.h"
 
 extern const grpc_channel_filter grpc_max_age_filter;
 
-#endif /* GRPC_CORE_LIB_CHANNEL_MAX_AGE_FILTER_H */
+#endif /* GRPC_CORE_EXT_FILTERS_MAX_AGE_MAX_AGE_FILTER_H */
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.c b/src/core/ext/transport/chttp2/client/chttp2_connector.c
index 2b226c1..e645eda 100644
--- a/src/core/ext/transport/chttp2/client/chttp2_connector.c
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.c
@@ -41,9 +41,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/connector.h"
-#include "src/core/ext/client_channel/http_connect_handshaker.h"
-#include "src/core/ext/client_channel/subchannel.h"
+#include "src/core/ext/filters/client_channel/connector.h"
+#include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
+#include "src/core/ext/filters/client_channel/subchannel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/handshaker.h"
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.h b/src/core/ext/transport/chttp2/client/chttp2_connector.h
index f5d1025..d55f6ed 100644
--- a/src/core/ext/transport/chttp2/client/chttp2_connector.h
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.h
@@ -34,7 +34,7 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H
 
-#include "src/core/ext/client_channel/connector.h"
+#include "src/core/ext/filters/client_channel/connector.h"
 
 grpc_connector* grpc_chttp2_connector_create();
 
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create.c b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
index 067ac35..9c8505d 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create.c
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
@@ -38,8 +38,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/surface/api_trace.h"
diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
index f0c241d..119adfa 100644
--- a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
+++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
@@ -38,9 +38,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
-#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
index f46e849..6ab176e 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
@@ -57,12 +57,9 @@
   char *name;
   gpr_asprintf(&name, "fd:%d", fd);
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_from_channel_args(
-      grpc_server_get_channel_args(server));
   grpc_endpoint *server_endpoint =
-      grpc_tcp_create(grpc_fd_create(fd, name), resource_quota,
-                      GRPC_TCP_DEFAULT_READ_SLICE_SIZE, name);
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+      grpc_tcp_create(&exec_ctx, grpc_fd_create(fd, name),
+                      grpc_server_get_channel_args(server), name);
 
   gpr_free(name);
 
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 73f9454..e2816b0 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -69,13 +69,21 @@
 #define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024)
 #define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024)
 
-#define DEFAULT_CLIENT_KEEPALIVE_TIME_S INT_MAX
-#define DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_S 20
+#define DEFAULT_CLIENT_KEEPALIVE_TIME_MS INT_MAX
+#define DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_MS 20000 /* 20 seconds */
+#define DEFAULT_SERVER_KEEPALIVE_TIME_MS 7200000  /* 2 hours */
+#define DEFAULT_SERVER_KEEPALIVE_TIMEOUT_MS 20000 /* 20 seconds */
 #define DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS false
+#define KEEPALIVE_TIME_BACKOFF_MULTIPLIER 2
 
-static int g_default_client_keepalive_time_s = DEFAULT_CLIENT_KEEPALIVE_TIME_S;
-static int g_default_client_keepalive_timeout_s =
-    DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_S;
+static int g_default_client_keepalive_time_ms =
+    DEFAULT_CLIENT_KEEPALIVE_TIME_MS;
+static int g_default_client_keepalive_timeout_ms =
+    DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_MS;
+static int g_default_server_keepalive_time_ms =
+    DEFAULT_SERVER_KEEPALIVE_TIME_MS;
+static int g_default_server_keepalive_timeout_ms =
+    DEFAULT_SERVER_KEEPALIVE_TIMEOUT_MS;
 static bool g_default_keepalive_permit_without_calls =
     DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS;
 
@@ -153,6 +161,8 @@
 
 #define DEFAULT_MIN_TIME_BETWEEN_PINGS_MS 0
 #define DEFAULT_MAX_PINGS_BETWEEN_DATA 3
+#define DEFAULT_MAX_PING_STRIKES 2
+#define DEFAULT_MIN_PING_INTERVAL_WITHOUT_DATA_MS 300000 /* 5 minutes */
 
 /** keepalive-relevant functions */
 static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg,
@@ -351,19 +361,35 @@
       .max_pings_without_data = DEFAULT_MAX_PINGS_BETWEEN_DATA,
       .min_time_between_pings =
           gpr_time_from_millis(DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, GPR_TIMESPAN),
+      .max_ping_strikes = DEFAULT_MAX_PING_STRIKES,
+      .min_ping_interval_without_data = gpr_time_from_millis(
+          DEFAULT_MIN_PING_INTERVAL_WITHOUT_DATA_MS, GPR_TIMESPAN),
   };
 
-  /* client-side keepalive setting */
-  t->keepalive_time =
-      g_default_client_keepalive_time_s == INT_MAX
-          ? gpr_inf_future(GPR_TIMESPAN)
-          : gpr_time_from_seconds(g_default_client_keepalive_time_s,
-                                  GPR_TIMESPAN);
-  t->keepalive_timeout =
-      g_default_client_keepalive_timeout_s == INT_MAX
-          ? gpr_inf_future(GPR_TIMESPAN)
-          : gpr_time_from_seconds(g_default_client_keepalive_timeout_s,
-                                  GPR_TIMESPAN);
+  /* Keepalive setting */
+  if (t->is_client) {
+    t->keepalive_time =
+        g_default_client_keepalive_time_ms == INT_MAX
+            ? gpr_inf_future(GPR_TIMESPAN)
+            : gpr_time_from_millis(g_default_client_keepalive_time_ms,
+                                   GPR_TIMESPAN);
+    t->keepalive_timeout =
+        g_default_client_keepalive_timeout_ms == INT_MAX
+            ? gpr_inf_future(GPR_TIMESPAN)
+            : gpr_time_from_millis(g_default_client_keepalive_timeout_ms,
+                                   GPR_TIMESPAN);
+  } else {
+    t->keepalive_time =
+        g_default_server_keepalive_time_ms == INT_MAX
+            ? gpr_inf_future(GPR_TIMESPAN)
+            : gpr_time_from_millis(g_default_server_keepalive_time_ms,
+                                   GPR_TIMESPAN);
+    t->keepalive_timeout =
+        g_default_server_keepalive_timeout_ms == INT_MAX
+            ? gpr_inf_future(GPR_TIMESPAN)
+            : gpr_time_from_millis(g_default_server_keepalive_timeout_ms,
+                                   GPR_TIMESPAN);
+  }
   t->keepalive_permit_without_calls = g_default_keepalive_permit_without_calls;
 
   if (channel_args) {
@@ -397,6 +423,11 @@
             &channel_args->args[i],
             (grpc_integer_options){DEFAULT_MAX_PINGS_BETWEEN_DATA, 0, INT_MAX});
       } else if (0 == strcmp(channel_args->args[i].key,
+                             GRPC_ARG_HTTP2_MAX_PING_STRIKES)) {
+        t->ping_policy.max_ping_strikes = grpc_channel_arg_get_integer(
+            &channel_args->args[i],
+            (grpc_integer_options){DEFAULT_MAX_PING_STRIKES, 0, INT_MAX});
+      } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS)) {
         t->ping_policy.min_time_between_pings = gpr_time_from_millis(
             grpc_channel_arg_get_integer(
@@ -404,6 +435,15 @@
                 (grpc_integer_options){DEFAULT_MIN_TIME_BETWEEN_PINGS_MS, 0,
                                        INT_MAX}),
             GPR_TIMESPAN);
+      } else if (0 ==
+                 strcmp(channel_args->args[i].key,
+                        GRPC_ARG_HTTP2_MIN_PING_INTERVAL_WITHOUT_DATA_MS)) {
+        t->ping_policy.min_ping_interval_without_data = gpr_time_from_millis(
+            grpc_channel_arg_get_integer(
+                &channel_args->args[i],
+                (grpc_integer_options){
+                    DEFAULT_MIN_PING_INTERVAL_WITHOUT_DATA_MS, 0, INT_MAX}),
+            GPR_TIMESPAN);
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE)) {
         t->write_buffer_size = (uint32_t)grpc_channel_arg_get_integer(
@@ -414,23 +454,27 @@
         t->enable_bdp_probe = grpc_channel_arg_get_integer(
             &channel_args->args[i], (grpc_integer_options){1, 0, 1});
       } else if (0 == strcmp(channel_args->args[i].key,
-                             GRPC_ARG_CLIENT_KEEPALIVE_TIME_S)) {
+                             GRPC_ARG_KEEPALIVE_TIME_MS)) {
         const int value = grpc_channel_arg_get_integer(
             &channel_args->args[i],
-            (grpc_integer_options){g_default_client_keepalive_time_s, 1,
-                                   INT_MAX});
+            (grpc_integer_options){t->is_client
+                                       ? g_default_client_keepalive_time_ms
+                                       : g_default_server_keepalive_time_ms,
+                                   1, INT_MAX});
         t->keepalive_time = value == INT_MAX
                                 ? gpr_inf_future(GPR_TIMESPAN)
-                                : gpr_time_from_seconds(value, GPR_TIMESPAN);
+                                : gpr_time_from_millis(value, GPR_TIMESPAN);
       } else if (0 == strcmp(channel_args->args[i].key,
-                             GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S)) {
+                             GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
         const int value = grpc_channel_arg_get_integer(
             &channel_args->args[i],
-            (grpc_integer_options){g_default_client_keepalive_timeout_s, 0,
-                                   INT_MAX});
+            (grpc_integer_options){t->is_client
+                                       ? g_default_client_keepalive_timeout_ms
+                                       : g_default_server_keepalive_timeout_ms,
+                                   0, INT_MAX});
         t->keepalive_timeout = value == INT_MAX
                                    ? gpr_inf_future(GPR_TIMESPAN)
-                                   : gpr_time_from_seconds(value, GPR_TIMESPAN);
+                                   : gpr_time_from_millis(value, GPR_TIMESPAN);
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
         t->keepalive_permit_without_calls =
@@ -488,8 +532,11 @@
       t->ping_policy.max_pings_without_data;
   t->ping_state.is_delayed_ping_timer_set = false;
 
-  /** Start client-side keepalive pings */
-  if (t->is_client) {
+  t->ping_recv_state.last_ping_recv_time = gpr_inf_past(GPR_CLOCK_MONOTONIC);
+  t->ping_recv_state.ping_strikes = 0;
+
+  /* Start keepalive pings */
+  if (gpr_time_cmp(t->keepalive_time, gpr_inf_future(GPR_TIMESPAN)) != 0) {
     t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING;
     GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
     grpc_timer_init(
@@ -918,6 +965,26 @@
   // GRPC_CHTTP2_IF_TRACING(
   //     gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
   t->seen_goaway = 1;
+
+  /* When a client receives a GOAWAY with error code ENHANCE_YOUR_CALM and debug
+   * data equal to “too_many_pings”, it should log the occurrence at a log level
+   * that is enabled by default and double the configured KEEPALIVE_TIME used
+   * for new connections on that channel. */
+  if (t->is_client && goaway_error == GRPC_HTTP2_ENHANCE_YOUR_CALM &&
+      grpc_slice_str_cmp(goaway_text, "too_many_pings") == 0) {
+    gpr_log(GPR_ERROR,
+            "Received a GOAWAY with error code ENHANCE_YOUR_CALM and debug "
+            "data equal to \"too_many_pings\"");
+    double current_keepalive_time_ms =
+        gpr_timespec_to_micros(t->keepalive_time) / 1000;
+    t->keepalive_time =
+        current_keepalive_time_ms > INT_MAX / KEEPALIVE_TIME_BACKOFF_MULTIPLIER
+            ? gpr_inf_future(GPR_TIMESPAN)
+            : gpr_time_from_millis((int64_t)(current_keepalive_time_ms *
+                                             KEEPALIVE_TIME_BACKOFF_MULTIPLIER),
+                                   GPR_TIMESPAN);
+  }
+
   /* lie: use transient failure from the transport to indicate goaway has been
    * received */
   connectivity_state_set(
@@ -1102,7 +1169,7 @@
       return; /* early out */
     } else if (grpc_byte_stream_next(exec_ctx, s->fetching_send_message,
                                      &s->fetching_slice, UINT32_MAX,
-                                     &s->complete_fetch)) {
+                                     &s->complete_fetch_locked)) {
       add_fetched_slice_locked(exec_ctx, t, s);
     }
   }
@@ -1140,20 +1207,23 @@
                                      grpc_error *error_ignored) {
   GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
 
-  grpc_transport_stream_op *op = stream_op;
-  grpc_chttp2_transport *t = op->handler_private.args[0];
-  grpc_chttp2_stream *s = op->handler_private.args[1];
+  grpc_transport_stream_op_batch *op = stream_op;
+  grpc_chttp2_stream *s = op->handler_private.extra_arg;
+  grpc_transport_stream_op_batch_payload *op_payload = op->payload;
+  grpc_chttp2_transport *t = s->t;
 
   if (grpc_http_trace) {
-    char *str = grpc_transport_stream_op_string(op);
+    char *str = grpc_transport_stream_op_batch_string(op);
     gpr_log(GPR_DEBUG, "perform_stream_op_locked: %s; on_complete = %p", str,
             op->on_complete);
     gpr_free(str);
     if (op->send_initial_metadata) {
-      log_metadata(op->send_initial_metadata, s->id, t->is_client, true);
+      log_metadata(op_payload->send_initial_metadata.send_initial_metadata,
+                   s->id, t->is_client, true);
     }
     if (op->send_trailing_metadata) {
-      log_metadata(op->send_trailing_metadata, s->id, t->is_client, false);
+      log_metadata(op_payload->send_trailing_metadata.send_trailing_metadata,
+                   s->id, t->is_client, false);
     }
   }
 
@@ -1168,23 +1238,25 @@
   on_complete->next_data.scratch = CLOSURE_BARRIER_FIRST_REF_BIT;
   on_complete->error_data.error = GRPC_ERROR_NONE;
 
-  if (op->collect_stats != NULL) {
+  if (op->collect_stats) {
     GPR_ASSERT(s->collecting_stats == NULL);
-    s->collecting_stats = op->collect_stats;
+    s->collecting_stats = op_payload->collect_stats.collect_stats;
     on_complete->next_data.scratch |= CLOSURE_BARRIER_STATS_BIT;
   }
 
-  if (op->cancel_error != GRPC_ERROR_NONE) {
-    grpc_chttp2_cancel_stream(exec_ctx, t, s, op->cancel_error);
+  if (op->cancel_stream) {
+    grpc_chttp2_cancel_stream(exec_ctx, t, s,
+                              op_payload->cancel_stream.cancel_error);
   }
 
-  if (op->send_initial_metadata != NULL) {
+  if (op->send_initial_metadata) {
     GPR_ASSERT(s->send_initial_metadata_finished == NULL);
     on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
     s->send_initial_metadata_finished = add_closure_barrier(on_complete);
-    s->send_initial_metadata = op->send_initial_metadata;
+    s->send_initial_metadata =
+        op_payload->send_initial_metadata.send_initial_metadata;
     const size_t metadata_size =
-        grpc_metadata_batch_size(op->send_initial_metadata);
+        grpc_metadata_batch_size(s->send_initial_metadata);
     const size_t metadata_peer_limit =
         t->settings[GRPC_PEER_SETTINGS]
                    [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
@@ -1205,7 +1277,7 @@
                   GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit),
               GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
     } else {
-      if (contains_non_ok_status(op->send_initial_metadata)) {
+      if (contains_non_ok_status(s->send_initial_metadata)) {
         s->seen_error = true;
       }
       if (!s->write_closed) {
@@ -1225,8 +1297,9 @@
           GPR_ASSERT(s->id != 0);
           grpc_chttp2_stream_write_type write_type =
               GRPC_CHTTP2_STREAM_WRITE_INITIATE_COVERED;
-          if (op->send_message != NULL &&
-              (op->send_message->flags & GRPC_WRITE_BUFFER_HINT)) {
+          if (op->send_message &&
+              (op->payload->send_message.send_message->flags &
+               GRPC_WRITE_BUFFER_HINT)) {
             write_type = GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK;
           }
           grpc_chttp2_become_writable(exec_ctx, t, s, write_type,
@@ -1244,7 +1317,7 @@
     }
   }
 
-  if (op->send_message != NULL) {
+  if (op->send_message) {
     on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
     s->fetching_send_message_finished = add_closure_barrier(op->on_complete);
     if (s->write_closed) {
@@ -1258,14 +1331,14 @@
       GPR_ASSERT(s->fetching_send_message == NULL);
       uint8_t *frame_hdr =
           grpc_slice_buffer_tiny_add(&s->flow_controlled_buffer, 5);
-      uint32_t flags = op->send_message->flags;
+      uint32_t flags = op_payload->send_message.send_message->flags;
       frame_hdr[0] = (flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0;
-      size_t len = op->send_message->length;
+      size_t len = op_payload->send_message.send_message->length;
       frame_hdr[1] = (uint8_t)(len >> 24);
       frame_hdr[2] = (uint8_t)(len >> 16);
       frame_hdr[3] = (uint8_t)(len >> 8);
       frame_hdr[4] = (uint8_t)(len);
-      s->fetching_send_message = op->send_message;
+      s->fetching_send_message = op_payload->send_message.send_message;
       s->fetched_send_message_length = 0;
       s->next_message_end_offset = s->flow_controlled_bytes_written +
                                    (int64_t)s->flow_controlled_buffer.length +
@@ -1282,14 +1355,15 @@
     }
   }
 
-  if (op->send_trailing_metadata != NULL) {
+  if (op->send_trailing_metadata) {
     GPR_ASSERT(s->send_trailing_metadata_finished == NULL);
     on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
     s->send_trailing_metadata_finished = add_closure_barrier(on_complete);
-    s->send_trailing_metadata = op->send_trailing_metadata;
+    s->send_trailing_metadata =
+        op_payload->send_trailing_metadata.send_trailing_metadata;
     s->write_buffering = false;
     const size_t metadata_size =
-        grpc_metadata_batch_size(op->send_trailing_metadata);
+        grpc_metadata_batch_size(s->send_trailing_metadata);
     const size_t metadata_peer_limit =
         t->settings[GRPC_PEER_SETTINGS]
                    [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
@@ -1306,14 +1380,15 @@
                   GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit),
               GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
     } else {
-      if (contains_non_ok_status(op->send_trailing_metadata)) {
+      if (contains_non_ok_status(s->send_trailing_metadata)) {
         s->seen_error = true;
       }
       if (s->write_closed) {
         s->send_trailing_metadata = NULL;
         grpc_chttp2_complete_closure_step(
             exec_ctx, t, s, &s->send_trailing_metadata_finished,
-            grpc_metadata_batch_is_empty(op->send_trailing_metadata)
+            grpc_metadata_batch_is_empty(
+                op->payload->send_trailing_metadata.send_trailing_metadata)
                 ? GRPC_ERROR_NONE
                 : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                       "Attempt to send trailing metadata after "
@@ -1329,17 +1404,19 @@
     }
   }
 
-  if (op->recv_initial_metadata != NULL) {
+  if (op->recv_initial_metadata) {
     GPR_ASSERT(s->recv_initial_metadata_ready == NULL);
-    s->recv_initial_metadata_ready = op->recv_initial_metadata_ready;
-    s->recv_initial_metadata = op->recv_initial_metadata;
+    s->recv_initial_metadata_ready =
+        op_payload->recv_initial_metadata.recv_initial_metadata_ready;
+    s->recv_initial_metadata =
+        op_payload->recv_initial_metadata.recv_initial_metadata;
     grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s);
   }
 
-  if (op->recv_message != NULL) {
+  if (op->recv_message) {
     GPR_ASSERT(s->recv_message_ready == NULL);
-    s->recv_message_ready = op->recv_message_ready;
-    s->recv_message = op->recv_message;
+    s->recv_message_ready = op_payload->recv_message.recv_message_ready;
+    s->recv_message = op_payload->recv_message.recv_message;
     if (s->id != 0 &&
         (s->incoming_frames.head == NULL || s->incoming_frames.head->is_tail)) {
       incoming_byte_stream_update_flow_control(exec_ctx, t, s, 5, 0);
@@ -1347,10 +1424,11 @@
     grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
   }
 
-  if (op->recv_trailing_metadata != NULL) {
+  if (op->recv_trailing_metadata) {
     GPR_ASSERT(s->recv_trailing_metadata_finished == NULL);
     s->recv_trailing_metadata_finished = add_closure_barrier(on_complete);
-    s->recv_trailing_metadata = op->recv_trailing_metadata;
+    s->recv_trailing_metadata =
+        op_payload->recv_trailing_metadata.recv_trailing_metadata;
     s->final_metadata_requested = true;
     grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
   }
@@ -1363,19 +1441,19 @@
 }
 
 static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                              grpc_stream *gs, grpc_transport_stream_op *op) {
+                              grpc_stream *gs,
+                              grpc_transport_stream_op_batch *op) {
   GPR_TIMER_BEGIN("perform_stream_op", 0);
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
   grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
 
   if (grpc_http_trace) {
-    char *str = grpc_transport_stream_op_string(op);
+    char *str = grpc_transport_stream_op_batch_string(op);
     gpr_log(GPR_DEBUG, "perform_stream_op[s=%p/%d]: %s", s, s->id, str);
     gpr_free(str);
   }
 
-  op->handler_private.args[0] = gt;
-  op->handler_private.args[1] = gs;
+  op->handler_private.extra_arg = gs;
   GRPC_CHTTP2_STREAM_REF(s, "perform_stream_op");
   grpc_closure_sched(
       exec_ctx,
@@ -1448,11 +1526,26 @@
   GRPC_ERROR_UNREF(error);
 }
 
+void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx,
+                                 grpc_chttp2_transport *t) {
+  gpr_log(GPR_DEBUG, "PING strike");
+  if (++t->ping_recv_state.ping_strikes > t->ping_policy.max_ping_strikes &&
+      t->ping_policy.max_ping_strikes != 0) {
+    send_goaway(exec_ctx, t,
+                grpc_error_set_int(
+                    GRPC_ERROR_CREATE_FROM_STATIC_STRING("too_many_pings"),
+                    GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM));
+    /*The transport will be closed after the write is done */
+    close_transport_locked(
+        exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"));
+  }
+}
+
 static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
                                         void *stream_op,
                                         grpc_error *error_ignored) {
   grpc_transport_op *op = stream_op;
-  grpc_chttp2_transport *t = op->transport_private.args[0];
+  grpc_chttp2_transport *t = op->handler_private.extra_arg;
   grpc_error *close_transport = op->disconnect_with_error;
 
   if (op->on_connectivity_state_change != NULL) {
@@ -1498,10 +1591,10 @@
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
   char *msg = grpc_transport_op_string(op);
   gpr_free(msg);
-  op->transport_private.args[0] = gt;
+  op->handler_private.extra_arg = gt;
   GRPC_CHTTP2_REF_TRANSPORT(t, "transport_op");
   grpc_closure_sched(
-      exec_ctx, grpc_closure_init(&op->transport_private.closure,
+      exec_ctx, grpc_closure_init(&op->handler_private.closure,
                                   perform_transport_op_locked, op,
                                   grpc_combiner_scheduler(t->combiner, false)),
       GRPC_ERROR_NONE);
@@ -2114,6 +2207,10 @@
   if (grpc_http_trace) {
     gpr_log(GPR_DEBUG, "%s: Start BDP ping", t->peer_string);
   }
+  /* Reset the keepalive ping timer */
+  if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING) {
+    grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
+  }
   grpc_bdp_estimator_start_ping(&t->bdp_estimator);
 }
 
@@ -2128,20 +2225,32 @@
   GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping");
 }
 
-void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args) {
+void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args,
+                                               bool is_client) {
   size_t i;
   if (args) {
     for (i = 0; i < args->num_args; i++) {
-      if (0 == strcmp(args->args[i].key, GRPC_ARG_CLIENT_KEEPALIVE_TIME_S)) {
-        g_default_client_keepalive_time_s = grpc_channel_arg_get_integer(
-            &args->args[i], (grpc_integer_options){
-                                g_default_client_keepalive_time_s, 1, INT_MAX});
-      } else if (0 == strcmp(args->args[i].key,
-                             GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S)) {
-        g_default_client_keepalive_timeout_s = grpc_channel_arg_get_integer(
+      if (0 == strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) {
+        const int value = grpc_channel_arg_get_integer(
             &args->args[i],
-            (grpc_integer_options){g_default_client_keepalive_timeout_s, 0,
+            (grpc_integer_options){g_default_client_keepalive_time_ms, 1,
                                    INT_MAX});
+        if (is_client) {
+          g_default_client_keepalive_time_ms = value;
+        } else {
+          g_default_server_keepalive_time_ms = value;
+        }
+      } else if (0 ==
+                 strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
+        const int value = grpc_channel_arg_get_integer(
+            &args->args[i],
+            (grpc_integer_options){g_default_client_keepalive_timeout_ms, 0,
+                                   INT_MAX});
+        if (is_client) {
+          g_default_client_keepalive_timeout_ms = value;
+        } else {
+          g_default_server_keepalive_timeout_ms = value;
+        }
       } else if (0 == strcmp(args->args[i].key,
                              GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) {
         g_default_keepalive_permit_without_calls =
@@ -2159,7 +2268,8 @@
   grpc_chttp2_transport *t = arg;
   GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING);
   if (error == GRPC_ERROR_NONE && !(t->destroying || t->closed)) {
-    if (t->keepalive_permit_without_calls || t->stream_map.count > 0) {
+    if (t->keepalive_permit_without_calls ||
+        grpc_chttp2_stream_map_size(&t->stream_map) > 0) {
       t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_PINGING;
       GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive ping end");
       send_ping_locked(exec_ctx, t, GRPC_CHTTP2_PING_ON_NEXT_WRITE,
@@ -2172,6 +2282,13 @@
           gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time),
           &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC));
     }
+  } else if (error == GRPC_ERROR_CANCELLED && !(t->destroying || t->closed)) {
+    /* The keepalive ping timer may be cancelled by bdp */
+    GRPC_CHTTP2_REF_TRANSPORT(t, "init keepalive ping");
+    grpc_timer_init(
+        exec_ctx, &t->keepalive_ping_timer,
+        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time),
+        &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC));
   }
   GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "init keepalive ping");
 }
@@ -2213,8 +2330,8 @@
                                               "keepalive watchdog timeout"));
     }
   } else {
-    /** The watchdog timer should have been cancelled by
-        finish_keepalive_ping_locked. */
+    /* The watchdog timer should have been cancelled by
+     * finish_keepalive_ping_locked. */
     if (error != GRPC_ERROR_CANCELLED) {
       gpr_log(GPR_ERROR, "keepalive_ping_end state error: %d (expect: %d)",
               t->keepalive_state, GRPC_CHTTP2_KEEPALIVE_STATE_PINGING);
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c
index 46dafdb..6016e43 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.c
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.c
@@ -103,6 +103,28 @@
     if (p->is_ack) {
       grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes);
     } else {
+      if (!t->is_client) {
+        gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+        gpr_timespec next_allowed_ping =
+            gpr_time_add(t->ping_recv_state.last_ping_recv_time,
+                         t->ping_policy.min_ping_interval_without_data);
+
+        if (t->keepalive_permit_without_calls == 0 &&
+            grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
+          /* According to RFC1122, the interval of TCP Keep-Alive is default to
+             no less than two hours. When there is no outstanding streams, we
+             restrict the number of PINGS equivalent to TCP Keep-Alive. */
+          next_allowed_ping =
+              gpr_time_add(t->ping_recv_state.last_ping_recv_time,
+                           gpr_time_from_seconds(7200, GPR_TIMESPAN));
+        }
+
+        if (gpr_time_cmp(next_allowed_ping, now) > 0) {
+          grpc_chttp2_add_ping_strike(exec_ctx, t);
+        }
+
+        t->ping_recv_state.last_ping_recv_time = now;
+      }
       if (!g_disable_ping_ack) {
         if (t->ping_ack_count == t->ping_ack_capacity) {
           t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3);
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 8b718e9..6eb848b 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -97,6 +97,8 @@
 typedef struct {
   gpr_timespec min_time_between_pings;
   int max_pings_without_data;
+  int max_ping_strikes;
+  gpr_timespec min_ping_interval_without_data;
 } grpc_chttp2_repeated_ping_policy;
 
 typedef struct {
@@ -106,6 +108,11 @@
   bool is_delayed_ping_timer_set;
 } grpc_chttp2_repeated_ping_state;
 
+typedef struct {
+  gpr_timespec last_ping_recv_time;
+  int ping_strikes;
+} grpc_chttp2_server_ping_recv_state;
+
 /* deframer state for the overall http2 stream of bytes */
 typedef enum {
   /* prefix: one entry per http2 connection prefix byte */
@@ -316,6 +323,7 @@
   size_t ping_ack_count;
   size_t ping_ack_capacity;
   uint64_t *ping_acks;
+  grpc_chttp2_server_ping_recv_state ping_recv_state;
 
   /** parser for headers */
   grpc_chttp2_hpack_parser hpack_parser;
@@ -452,7 +460,6 @@
   int64_t next_message_end_offset;
   int64_t flow_controlled_bytes_written;
   bool complete_fetch_covered_by_poller;
-  grpc_closure complete_fetch;
   grpc_closure complete_fetch_locked;
   grpc_closure *fetching_send_message_finished;
 
@@ -793,6 +800,13 @@
 void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                           uint64_t id);
 
+/** Add a new ping strike to ping_recv_state.ping_strikes. If
+    ping_recv_state.ping_strikes > ping_policy.max_ping_strikes, it sends GOAWAY
+    with error code ENHANCE_YOUR_CALM and additional debug data resembling
+    “too_many_pings” followed by immediately closing the connection. */
+void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx,
+                                 grpc_chttp2_transport *t);
+
 typedef enum {
   /* don't initiate a transport write, but piggyback on the next one */
   GRPC_CHTTP2_STREAM_WRITE_PIGGYBACK,
@@ -832,6 +846,7 @@
 
 /** Set the default keepalive configurations, must only be called at
     initialization */
-void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args);
+void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args,
+                                               bool is_client);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index 0869056..be41b3d 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -229,6 +229,11 @@
       now_writing = true;
       t->ping_state.pings_before_data_required =
           t->ping_policy.max_pings_without_data;
+      if (!t->is_client) {
+        t->ping_recv_state.last_ping_recv_time =
+            gpr_inf_past(GPR_CLOCK_MONOTONIC);
+        t->ping_recv_state.ping_strikes = 0;
+      }
     }
     /* send any window updates */
     if (s->announce_window > 0) {
@@ -238,6 +243,11 @@
                                 s->id, s->announce_window, &s->stats.outgoing));
       t->ping_state.pings_before_data_required =
           t->ping_policy.max_pings_without_data;
+      if (!t->is_client) {
+        t->ping_recv_state.last_ping_recv_time =
+            gpr_inf_past(GPR_CLOCK_MONOTONIC);
+        t->ping_recv_state.ping_strikes = 0;
+      }
       GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, announce_window, announce);
     }
     if (sent_initial_metadata) {
@@ -270,6 +280,11 @@
                                            send_bytes);
           t->ping_state.pings_before_data_required =
               t->ping_policy.max_pings_without_data;
+          if (!t->is_client) {
+            t->ping_recv_state.last_ping_recv_time =
+                gpr_inf_past(GPR_CLOCK_MONOTONIC);
+            t->ping_recv_state.ping_strikes = 0;
+          }
           if (is_last_frame) {
             s->send_trailing_metadata = NULL;
             s->sent_trailing_metadata = true;
@@ -345,6 +360,11 @@
                                           0, announced, &throwaway_stats));
     t->ping_state.pings_before_data_required =
         t->ping_policy.max_pings_without_data;
+    if (!t->is_client) {
+      t->ping_recv_state.last_ping_recv_time =
+          gpr_inf_past(GPR_CLOCK_MONOTONIC);
+      t->ping_recv_state.ping_strikes = 0;
+    }
   }
 
   for (size_t i = 0; i < t->ping_ack_count; i++) {
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c
index 952690e..0b91895 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.c
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -172,7 +172,7 @@
 };
 
 struct op_and_state {
-  grpc_transport_stream_op op;
+  grpc_transport_stream_op_batch op;
   struct op_state state;
   bool done;
   struct stream_obj *s;      /* Pointer back to the stream object */
@@ -187,7 +187,7 @@
 struct stream_obj {
   gpr_arena *arena;
   struct op_and_state *oas;
-  grpc_transport_stream_op *curr_op;
+  grpc_transport_stream_op_batch *curr_op;
   grpc_cronet_transport *curr_ct;
   grpc_stream *curr_gs;
   bidirectional_stream *cbs;
@@ -298,12 +298,13 @@
 /*
   Add a new stream op to op storage.
 */
-static void add_to_storage(struct stream_obj *s, grpc_transport_stream_op *op) {
+static void add_to_storage(struct stream_obj *s,
+                           grpc_transport_stream_op_batch *op) {
   struct op_storage *storage = &s->storage;
   /* add new op at the beginning of the linked list. The memory is freed
   in remove_from_storage */
   struct op_and_state *new_op = gpr_malloc(sizeof(struct op_and_state));
-  memcpy(&new_op->op, op, sizeof(grpc_transport_stream_op));
+  memcpy(&new_op->op, op, sizeof(grpc_transport_stream_op_batch));
   memset(&new_op->state, 0, sizeof(new_op->state));
   new_op->s = s;
   new_op->done = false;
@@ -768,7 +769,7 @@
   Op Execution: Decide if one of the actions contained in the stream op can be
   executed. This is the heart of the state machine.
 */
-static bool op_can_be_run(grpc_transport_stream_op *curr_op,
+static bool op_can_be_run(grpc_transport_stream_op_batch *curr_op,
                           struct stream_obj *s, struct op_state *op_state,
                           enum e_op_id op_id) {
   struct op_state *stream_state = &s->state;
@@ -919,7 +920,7 @@
 */
 static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
                                           struct op_and_state *oas) {
-  grpc_transport_stream_op *stream_op = &oas->op;
+  grpc_transport_stream_op_batch *stream_op = &oas->op;
   struct stream_obj *s = oas->s;
   grpc_cronet_transport *t = (grpc_cronet_transport *)s->curr_ct;
   struct op_state *stream_state = &s->state;
@@ -941,9 +942,10 @@
     char *url = NULL;
     const char *method = "POST";
     s->header_array.headers = NULL;
-    convert_metadata_to_cronet_headers(
-        stream_op->send_initial_metadata->list.head, t->host, &url,
-        &s->header_array.headers, &s->header_array.count, &method);
+    convert_metadata_to_cronet_headers(stream_op->payload->send_initial_metadata
+                                           .send_initial_metadata->list.head,
+                                       t->host, &url, &s->header_array.headers,
+                                       &s->header_array.count, &method);
     s->header_array.capacity = s->header_array.count;
     CRONET_LOG(GPR_DEBUG, "bidirectional_stream_start(%p, %s)", s->cbs, url);
     bidirectional_stream_start(s->cbs, url, 0, method, &s->header_array, false);
@@ -971,8 +973,9 @@
       grpc_slice_buffer write_slice_buffer;
       grpc_slice slice;
       grpc_slice_buffer_init(&write_slice_buffer);
-      grpc_byte_stream_next(NULL, stream_op->send_message, &slice,
-                            stream_op->send_message->length, NULL);
+      grpc_byte_stream_next(
+          NULL, stream_op->payload->send_message.send_message, &slice,
+          stream_op->payload->send_message.send_message->length, NULL);
       grpc_slice_buffer_add(&write_slice_buffer, slice);
       if (write_slice_buffer.count != 1) {
         /* Empty request not handled yet */
@@ -982,7 +985,8 @@
       if (write_slice_buffer.count > 0) {
         size_t write_buffer_size;
         create_grpc_frame(&write_slice_buffer, &stream_state->ws.write_buffer,
-                          &write_buffer_size, stream_op->send_message->flags);
+                          &write_buffer_size,
+                          stream_op->payload->send_message.send_message->flags);
         CRONET_LOG(GPR_DEBUG, "bidirectional_stream_write (%p, %p)", s->cbs,
                    stream_state->ws.write_buffer);
         stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
@@ -1029,20 +1033,28 @@
                            OP_RECV_INITIAL_METADATA)) {
     CRONET_LOG(GPR_DEBUG, "running: %p  OP_RECV_INITIAL_METADATA", oas);
     if (stream_state->state_op_done[OP_CANCEL_ERROR]) {
-      grpc_closure_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
-                         GRPC_ERROR_NONE);
+      grpc_closure_sched(
+          exec_ctx,
+          stream_op->payload->recv_initial_metadata.recv_initial_metadata_ready,
+          GRPC_ERROR_NONE);
     } else if (stream_state->state_callback_received[OP_FAILED]) {
-      grpc_closure_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
-                         GRPC_ERROR_NONE);
+      grpc_closure_sched(
+          exec_ctx,
+          stream_op->payload->recv_initial_metadata.recv_initial_metadata_ready,
+          GRPC_ERROR_NONE);
     } else if (stream_state->state_op_done[OP_RECV_TRAILING_METADATA]) {
-      grpc_closure_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
-                         GRPC_ERROR_NONE);
+      grpc_closure_sched(
+          exec_ctx,
+          stream_op->payload->recv_initial_metadata.recv_initial_metadata_ready,
+          GRPC_ERROR_NONE);
     } else {
       grpc_chttp2_incoming_metadata_buffer_publish(
           exec_ctx, &oas->s->state.rs.initial_metadata,
-          stream_op->recv_initial_metadata);
-      grpc_closure_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
-                         GRPC_ERROR_NONE);
+          stream_op->payload->recv_initial_metadata.recv_initial_metadata);
+      grpc_closure_sched(
+          exec_ctx,
+          stream_op->payload->recv_initial_metadata.recv_initial_metadata_ready,
+          GRPC_ERROR_NONE);
     }
     stream_state->state_op_done[OP_RECV_INITIAL_METADATA] = true;
     result = ACTION_TAKEN_NO_CALLBACK;
@@ -1051,27 +1063,31 @@
     CRONET_LOG(GPR_DEBUG, "running: %p  OP_RECV_MESSAGE", oas);
     if (stream_state->state_op_done[OP_CANCEL_ERROR]) {
       CRONET_LOG(GPR_DEBUG, "Stream is cancelled.");
-      grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
+      grpc_closure_sched(exec_ctx,
+                         stream_op->payload->recv_message.recv_message_ready,
                          GRPC_ERROR_NONE);
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
       result = ACTION_TAKEN_NO_CALLBACK;
     } else if (stream_state->state_callback_received[OP_FAILED]) {
       CRONET_LOG(GPR_DEBUG, "Stream failed.");
-      grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
+      grpc_closure_sched(exec_ctx,
+                         stream_op->payload->recv_message.recv_message_ready,
                          GRPC_ERROR_NONE);
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
       result = ACTION_TAKEN_NO_CALLBACK;
     } else if (stream_state->rs.read_stream_closed == true) {
       /* No more data will be received */
       CRONET_LOG(GPR_DEBUG, "read stream closed");
-      grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
+      grpc_closure_sched(exec_ctx,
+                         stream_op->payload->recv_message.recv_message_ready,
                          GRPC_ERROR_NONE);
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
       oas->state.state_op_done[OP_RECV_MESSAGE] = true;
       result = ACTION_TAKEN_NO_CALLBACK;
     } else if (stream_state->flush_read) {
       CRONET_LOG(GPR_DEBUG, "flush read");
-      grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
+      grpc_closure_sched(exec_ctx,
+                         stream_op->payload->recv_message.recv_message_ready,
                          GRPC_ERROR_NONE);
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
       oas->state.state_op_done[OP_RECV_MESSAGE] = true;
@@ -1110,8 +1126,9 @@
           }
           *((grpc_byte_buffer **)stream_op->recv_message) =
               (grpc_byte_buffer *)&stream_state->rs.sbs;
-          grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
-                             GRPC_ERROR_NONE);
+          grpc_closure_sched(
+              exec_ctx, stream_op->payload->recv_message.recv_message_ready,
+              GRPC_ERROR_NONE);
           stream_state->state_op_done[OP_RECV_MESSAGE] = true;
           oas->state.state_op_done[OP_RECV_MESSAGE] = true;
 
@@ -1161,9 +1178,10 @@
       if (stream_state->rs.compressed) {
         stream_state->rs.sbs.base.flags = GRPC_WRITE_INTERNAL_COMPRESS;
       }
-      *((grpc_byte_buffer **)stream_op->recv_message) =
+      *((grpc_byte_buffer **)stream_op->payload->recv_message.recv_message) =
           (grpc_byte_buffer *)&stream_state->rs.sbs;
-      grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
+      grpc_closure_sched(exec_ctx,
+                         stream_op->payload->recv_message.recv_message_ready,
                          GRPC_ERROR_NONE);
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
       oas->state.state_op_done[OP_RECV_MESSAGE] = true;
@@ -1187,12 +1205,12 @@
     if (oas->s->state.rs.trailing_metadata_valid) {
       grpc_chttp2_incoming_metadata_buffer_publish(
           exec_ctx, &oas->s->state.rs.trailing_metadata,
-          stream_op->recv_trailing_metadata);
+          stream_op->payload->recv_trailing_metadata.recv_trailing_metadata);
       stream_state->rs.trailing_metadata_valid = false;
     }
     stream_state->state_op_done[OP_RECV_TRAILING_METADATA] = true;
     result = ACTION_TAKEN_NO_CALLBACK;
-  } else if (stream_op->cancel_error &&
+  } else if (stream_op->cancel_stream &&
              op_can_be_run(stream_op, s, &oas->state, OP_CANCEL_ERROR)) {
     CRONET_LOG(GPR_DEBUG, "running: %p  OP_CANCEL_ERROR", oas);
     CRONET_LOG(GPR_DEBUG, "W: bidirectional_stream_cancel(%p)", s->cbs);
@@ -1204,7 +1222,8 @@
     }
     stream_state->state_op_done[OP_CANCEL_ERROR] = true;
     if (!stream_state->cancel_error) {
-      stream_state->cancel_error = GRPC_ERROR_REF(stream_op->cancel_error);
+      stream_state->cancel_error =
+          GRPC_ERROR_REF(stream_op->payload->cancel_stream.cancel_error);
     }
   } else if (stream_op->on_complete &&
              op_can_be_run(stream_op, s, &oas->state, OP_ON_COMPLETE)) {
@@ -1283,18 +1302,22 @@
                                        grpc_pollset_set *pollset_set) {}
 
 static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                              grpc_stream *gs, grpc_transport_stream_op *op) {
+                              grpc_stream *gs,
+                              grpc_transport_stream_op_batch *op) {
   CRONET_LOG(GPR_DEBUG, "perform_stream_op");
   if (op->send_initial_metadata &&
-      header_has_authority(op->send_initial_metadata->list.head)) {
+      header_has_authority(op->payload->send_initial_metadata
+                               .send_initial_metadata->list.head)) {
     /* Cronet does not support :authority header field. We cancel the call when
      this field is present in metadata */
-    if (op->recv_initial_metadata_ready) {
-      grpc_closure_sched(exec_ctx, op->recv_initial_metadata_ready,
-                         GRPC_ERROR_CANCELLED);
+    if (op->recv_initial_metadata) {
+      grpc_closure_sched(
+          exec_ctx,
+          op->payload->recv_initial_metadata.recv_initial_metadata_ready,
+          GRPC_ERROR_CANCELLED);
     }
-    if (op->recv_message_ready) {
-      grpc_closure_sched(exec_ctx, op->recv_message_ready,
+    if (op->recv_message) {
+      grpc_closure_sched(exec_ctx, op->payload->recv_message.recv_message_ready,
                          GRPC_ERROR_CANCELLED);
     }
     grpc_closure_sched(exec_ctx, op->on_complete, GRPC_ERROR_CANCELLED);
diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c
index 1a099ac..a6d124c 100644
--- a/src/core/lib/channel/channel_args.c
+++ b/src/core/lib/channel/channel_args.c
@@ -346,3 +346,10 @@
   }
   return arg->value.integer;
 }
+
+bool grpc_channel_args_want_minimal_stack(const grpc_channel_args *args) {
+  const grpc_arg *arg = grpc_channel_args_find(args, GRPC_ARG_MINIMAL_STACK);
+  if (arg == NULL) return false;
+  if (arg->type == GRPC_ARG_INTEGER && arg->value.integer == 0) return false;
+  return true;
+}
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 5c7d31f..158cda5 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -113,6 +113,8 @@
 const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args,
                                        const char *name);
 
+bool grpc_channel_args_want_minimal_stack(const grpc_channel_args *args);
+
 typedef struct grpc_integer_options {
   int default_value;  // Return this if value is outside of expected bounds.
   int min_value;
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 6d53b05..9438298 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -246,9 +246,9 @@
 }
 
 void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                       grpc_transport_stream_op *op) {
+                       grpc_transport_stream_op_batch *op) {
   grpc_call_element *next_elem = elem + 1;
-  next_elem->filter->start_transport_stream_op(exec_ctx, next_elem, op);
+  next_elem->filter->start_transport_stream_op_batch(exec_ctx, next_elem, op);
 }
 
 char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx,
@@ -284,7 +284,8 @@
 void grpc_call_element_signal_error(grpc_exec_ctx *exec_ctx,
                                     grpc_call_element *elem,
                                     grpc_error *error) {
-  grpc_transport_stream_op *op = grpc_make_transport_stream_op(NULL);
-  op->cancel_error = error;
-  elem->filter->start_transport_stream_op(exec_ctx, elem, op);
+  grpc_transport_stream_op_batch *op = grpc_make_transport_stream_op(NULL);
+  op->cancel_stream = true;
+  op->payload->cancel_stream.cancel_error = error;
+  elem->filter->start_transport_stream_op_batch(exec_ctx, elem, op);
 }
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 80e3603..fdbcbdb 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -112,9 +112,9 @@
 typedef struct {
   /* Called to eg. send/receive data on a call.
      See grpc_call_next_op on how to call the next element in the stack */
-  void (*start_transport_stream_op)(grpc_exec_ctx *exec_ctx,
-                                    grpc_call_element *elem,
-                                    grpc_transport_stream_op *op);
+  void (*start_transport_stream_op_batch)(grpc_exec_ctx *exec_ctx,
+                                          grpc_call_element *elem,
+                                          grpc_transport_stream_op_batch *op);
   /* Called to handle channel level operations - e.g. new calls, or transport
      closure.
      See grpc_channel_next_op on how to call the next element in the stack */
@@ -281,7 +281,7 @@
     grpc_polling_entity *pollent);
 /* Call the next operation in a call stack */
 void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                       grpc_transport_stream_op *op);
+                       grpc_transport_stream_op_batch *op);
 /* Call the next operation (depending on call directionality) in a channel
    stack */
 void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
@@ -300,7 +300,8 @@
 grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem);
 
 void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
-                      grpc_call_element *elem, grpc_transport_stream_op *op);
+                      grpc_call_element *elem,
+                      grpc_transport_stream_op_batch *op);
 
 void grpc_call_element_signal_error(grpc_exec_ctx *exec_ctx,
                                     grpc_call_element *cur_elem,
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 02dc479..4625cba 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -62,7 +62,7 @@
   /** If true, contents of \a compression_algorithm are authoritative */
   int has_compression_algorithm;
 
-  grpc_transport_stream_op *send_op;
+  grpc_transport_stream_op_batch *send_op;
   uint32_t send_length;
   uint32_t send_flags;
   grpc_slice incoming_slice;
@@ -210,7 +210,8 @@
 
   grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
                                 calld->send_flags);
-  calld->send_op->send_message = &calld->replacement_stream.base;
+  calld->send_op->payload->send_message.send_message =
+      &calld->replacement_stream.base;
   calld->post_send = calld->send_op->on_complete;
   calld->send_op->on_complete = &calld->send_done;
 
@@ -231,9 +232,9 @@
 static void continue_send_message(grpc_exec_ctx *exec_ctx,
                                   grpc_call_element *elem) {
   call_data *calld = elem->call_data;
-  while (grpc_byte_stream_next(exec_ctx, calld->send_op->send_message,
-                               &calld->incoming_slice, ~(size_t)0,
-                               &calld->got_slice)) {
+  while (grpc_byte_stream_next(
+      exec_ctx, calld->send_op->payload->send_message.send_message,
+      &calld->incoming_slice, ~(size_t)0, &calld->got_slice)) {
     grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
     if (calld->send_length == calld->slices.length) {
       finish_send_message(exec_ctx, elem);
@@ -242,33 +243,34 @@
   }
 }
 
-static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                               grpc_call_element *elem,
-                                               grpc_transport_stream_op *op) {
+static void compress_start_transport_stream_op_batch(
+    grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+    grpc_transport_stream_op_batch *op) {
   call_data *calld = elem->call_data;
 
-  GPR_TIMER_BEGIN("compress_start_transport_stream_op", 0);
+  GPR_TIMER_BEGIN("compress_start_transport_stream_op_batch", 0);
 
   if (op->send_initial_metadata) {
     grpc_error *error = process_send_initial_metadata(
-        exec_ctx, elem, op->send_initial_metadata);
+        exec_ctx, elem,
+        op->payload->send_initial_metadata.send_initial_metadata);
     if (error != GRPC_ERROR_NONE) {
-      grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+      grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
       return;
     }
   }
-  if (op->send_message != NULL &&
-      !skip_compression(elem, op->send_message->flags)) {
+  if (op->send_message &&
+      !skip_compression(elem, op->payload->send_message.send_message->flags)) {
     calld->send_op = op;
-    calld->send_length = op->send_message->length;
-    calld->send_flags = op->send_message->flags;
+    calld->send_length = op->payload->send_message.send_message->length;
+    calld->send_flags = op->payload->send_message.send_message->flags;
     continue_send_message(exec_ctx, elem);
   } else {
     /* pass control down the stack */
     grpc_call_next_op(exec_ctx, elem, op);
   }
 
-  GPR_TIMER_END("compress_start_transport_stream_op", 0);
+  GPR_TIMER_END("compress_start_transport_stream_op_batch", 0);
 }
 
 /* Constructor for call_data */
@@ -337,7 +339,7 @@
                                  grpc_channel_element *elem) {}
 
 const grpc_channel_filter grpc_compress_filter = {
-    compress_start_transport_stream_op,
+    compress_start_transport_stream_op_batch,
     grpc_channel_next_op,
     sizeof(call_data),
     init_call_elem,
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index 75c68a5..22caf24 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -62,9 +62,9 @@
 
 /* Intercept a call operation and either push it directly up or translate it
    into transport stream operations */
-static void con_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                          grpc_call_element *elem,
-                                          grpc_transport_stream_op *op) {
+static void con_start_transport_stream_op_batch(
+    grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+    grpc_transport_stream_op_batch *op) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
@@ -142,7 +142,7 @@
                                  const grpc_channel_info *channel_info) {}
 
 const grpc_channel_filter grpc_connected_filter = {
-    con_start_transport_stream_op,
+    con_start_transport_stream_op_batch,
     con_start_transport_op,
     sizeof(call_data),
     init_call_elem,
diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c
index ca701ed..fda099b 100644
--- a/src/core/lib/channel/deadline_filter.c
+++ b/src/core/lib/channel/deadline_filter.c
@@ -134,7 +134,7 @@
 
 // Inject our own on_complete callback into op.
 static void inject_on_complete_cb(grpc_deadline_state* deadline_state,
-                                  grpc_transport_stream_op* op) {
+                                  grpc_transport_stream_op_batch* op) {
   deadline_state->next_on_complete = op->on_complete;
   grpc_closure_init(&deadline_state->on_complete, on_complete, deadline_state,
                     grpc_schedule_on_exec_ctx);
@@ -196,16 +196,16 @@
   start_timer_if_needed(exec_ctx, elem, new_deadline);
 }
 
-void grpc_deadline_state_client_start_transport_stream_op(
+void grpc_deadline_state_client_start_transport_stream_op_batch(
     grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
-    grpc_transport_stream_op* op) {
+    grpc_transport_stream_op_batch* op) {
   grpc_deadline_state* deadline_state = elem->call_data;
-  if (op->cancel_error != GRPC_ERROR_NONE) {
+  if (op->cancel_stream) {
     cancel_timer_if_needed(exec_ctx, deadline_state);
   } else {
     // Make sure we know when the call is complete, so that we can cancel
     // the timer.
-    if (op->recv_trailing_metadata != NULL) {
+    if (op->recv_trailing_metadata) {
       inject_on_complete_cb(deadline_state, op);
     }
   }
@@ -261,10 +261,11 @@
 }
 
 // Method for starting a call op for client filter.
-static void client_start_transport_stream_op(grpc_exec_ctx* exec_ctx,
-                                             grpc_call_element* elem,
-                                             grpc_transport_stream_op* op) {
-  grpc_deadline_state_client_start_transport_stream_op(exec_ctx, elem, op);
+static void client_start_transport_stream_op_batch(
+    grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
+    grpc_transport_stream_op_batch* op) {
+  grpc_deadline_state_client_start_transport_stream_op_batch(exec_ctx, elem,
+                                                             op);
   // Chain to next filter.
   grpc_call_next_op(exec_ctx, elem, op);
 }
@@ -282,30 +283,33 @@
 }
 
 // Method for starting a call op for server filter.
-static void server_start_transport_stream_op(grpc_exec_ctx* exec_ctx,
-                                             grpc_call_element* elem,
-                                             grpc_transport_stream_op* op) {
+static void server_start_transport_stream_op_batch(
+    grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
+    grpc_transport_stream_op_batch* op) {
   server_call_data* calld = elem->call_data;
-  if (op->cancel_error != GRPC_ERROR_NONE) {
+  if (op->cancel_stream) {
     cancel_timer_if_needed(exec_ctx, &calld->base.deadline_state);
   } else {
     // If we're receiving initial metadata, we need to get the deadline
     // from the recv_initial_metadata_ready callback.  So we inject our
     // own callback into that hook.
-    if (op->recv_initial_metadata_ready != NULL) {
-      calld->next_recv_initial_metadata_ready = op->recv_initial_metadata_ready;
-      calld->recv_initial_metadata = op->recv_initial_metadata;
+    if (op->recv_initial_metadata) {
+      calld->next_recv_initial_metadata_ready =
+          op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+      calld->recv_initial_metadata =
+          op->payload->recv_initial_metadata.recv_initial_metadata;
       grpc_closure_init(&calld->recv_initial_metadata_ready,
                         recv_initial_metadata_ready, elem,
                         grpc_schedule_on_exec_ctx);
-      op->recv_initial_metadata_ready = &calld->recv_initial_metadata_ready;
+      op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+          &calld->recv_initial_metadata_ready;
     }
     // Make sure we know when the call is complete, so that we can cancel
     // the timer.
     // Note that we trigger this on recv_trailing_metadata, even though
     // the client never sends trailing metadata, because this is the
     // hook that tells us when the call is complete on the server side.
-    if (op->recv_trailing_metadata != NULL) {
+    if (op->recv_trailing_metadata) {
       inject_on_complete_cb(&calld->base.deadline_state, op);
     }
   }
@@ -314,7 +318,7 @@
 }
 
 const grpc_channel_filter grpc_client_deadline_filter = {
-    client_start_transport_stream_op,
+    client_start_transport_stream_op_batch,
     grpc_channel_next_op,
     sizeof(base_call_data),
     init_call_elem,
@@ -329,7 +333,7 @@
 };
 
 const grpc_channel_filter grpc_server_deadline_filter = {
-    server_start_transport_stream_op,
+    server_start_transport_stream_op_batch,
     grpc_channel_next_op,
     sizeof(server_call_data),
     init_call_elem,
diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/lib/channel/deadline_filter.h
index 72cd5cb..d8db9a9 100644
--- a/src/core/lib/channel/deadline_filter.h
+++ b/src/core/lib/channel/deadline_filter.h
@@ -83,15 +83,15 @@
 void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
                                gpr_timespec new_deadline);
 
-// To be called from the client-side filter's start_transport_stream_op()
+// To be called from the client-side filter's start_transport_stream_op_batch()
 // method.  Ensures that the deadline timer is cancelled when the call
 // is completed.
 //
 // Note: It is the caller's responsibility to chain to the next filter if
 // necessary after this function returns.
-void grpc_deadline_state_client_start_transport_stream_op(
+void grpc_deadline_state_client_start_transport_stream_op_batch(
     grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
-    grpc_transport_stream_op* op);
+    grpc_transport_stream_op_batch* op);
 
 // Deadline filters for direct client channels and server channels.
 // Note: Deadlines for non-direct client channels are handled by the
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index 17af201..4e47c5c 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -63,7 +63,7 @@
   uint8_t *payload_bytes;
 
   /* Vars to read data off of send_message */
-  grpc_transport_stream_op send_op;
+  grpc_transport_stream_op_batch *send_op;
   uint32_t send_length;
   uint32_t send_flags;
   grpc_slice incoming_slice;
@@ -219,9 +219,9 @@
                                   grpc_call_element *elem) {
   call_data *calld = elem->call_data;
   uint8_t *wrptr = calld->payload_bytes;
-  while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message,
-                               &calld->incoming_slice, ~(size_t)0,
-                               &calld->got_slice)) {
+  while (grpc_byte_stream_next(
+      exec_ctx, calld->send_op->payload->send_message.send_message,
+      &calld->incoming_slice, ~(size_t)0, &calld->got_slice)) {
     memcpy(wrptr, GRPC_SLICE_START_PTR(calld->incoming_slice),
            GRPC_SLICE_LENGTH(calld->incoming_slice));
     wrptr += GRPC_SLICE_LENGTH(calld->incoming_slice);
@@ -242,10 +242,11 @@
     /* Pass down the original send_message op that was blocked.*/
     grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
                                   calld->send_flags);
-    calld->send_op.send_message = &calld->replacement_stream.base;
-    calld->post_send = calld->send_op.on_complete;
-    calld->send_op.on_complete = &calld->send_done;
-    grpc_call_next_op(exec_ctx, elem, &calld->send_op);
+    calld->send_op->payload->send_message.send_message =
+        &calld->replacement_stream.base;
+    calld->post_send = calld->send_op->on_complete;
+    calld->send_op->on_complete = &calld->send_done;
+    grpc_call_next_op(exec_ctx, elem, calld->send_op);
   } else {
     continue_send_message(exec_ctx, elem);
   }
@@ -253,29 +254,30 @@
 
 static grpc_error *hc_mutate_op(grpc_exec_ctx *exec_ctx,
                                 grpc_call_element *elem,
-                                grpc_transport_stream_op *op) {
+                                grpc_transport_stream_op_batch *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
   grpc_error *error;
 
-  if (op->send_initial_metadata != NULL) {
+  if (op->send_initial_metadata) {
     /* Decide which HTTP VERB to use. We use GET if the request is marked
     cacheable, and the operation contains both initial metadata and send
     message, and the payload is below the size threshold, and all the data
     for this request is immediately available. */
     grpc_mdelem method = GRPC_MDELEM_METHOD_POST;
-    if ((op->send_initial_metadata_flags &
+    if (op->send_message &&
+        (op->payload->send_initial_metadata.send_initial_metadata_flags &
          GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) &&
-        op->send_message != NULL &&
-        op->send_message->length < channeld->max_payload_size_for_get) {
+        op->payload->send_message.send_message->length <
+            channeld->max_payload_size_for_get) {
       method = GRPC_MDELEM_METHOD_GET;
       /* The following write to calld->send_message_blocked isn't racy with
       reads in hc_start_transport_op (which deals with SEND_MESSAGE ops) because
       being here means ops->send_message is not NULL, which is primarily
       guarding the read there. */
       calld->send_message_blocked = true;
-    } else if (op->send_initial_metadata_flags &
+    } else if (op->payload->send_initial_metadata.send_initial_metadata_flags &
                GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) {
       method = GRPC_MDELEM_METHOD_PUT;
     }
@@ -283,12 +285,13 @@
     /* Attempt to read the data from send_message and create a header field. */
     if (grpc_mdelem_eq(method, GRPC_MDELEM_METHOD_GET)) {
       /* allocate memory to hold the entire payload */
-      calld->payload_bytes = gpr_malloc(op->send_message->length);
+      calld->payload_bytes =
+          gpr_malloc(op->payload->send_message.send_message->length);
 
       /* read slices of send_message and copy into payload_bytes */
-      calld->send_op = *op;
-      calld->send_length = op->send_message->length;
-      calld->send_flags = op->send_message->flags;
+      calld->send_op = op;
+      calld->send_length = op->payload->send_message.send_message->length;
+      calld->send_flags = op->payload->send_message.send_message->flags;
       continue_send_message(exec_ctx, elem);
 
       if (calld->send_message_blocked == false) {
@@ -299,13 +302,15 @@
         const unsigned char k_query_separator = '?';
 
         grpc_slice path_slice =
-            GRPC_MDVALUE(op->send_initial_metadata->idx.named.path->md);
+            GRPC_MDVALUE(op->payload->send_initial_metadata
+                             .send_initial_metadata->idx.named.path->md);
         /* sum up individual component's lengths and allocate enough memory to
          * hold combined path+query */
         size_t estimated_len = GRPC_SLICE_LENGTH(path_slice);
         estimated_len++; /* for the '?' */
         estimated_len += grpc_base64_estimate_encoded_size(
-            op->send_message->length, k_url_safe, k_multi_line);
+            op->payload->send_message.send_message->length, k_url_safe,
+            k_multi_line);
         estimated_len += 1; /* for the trailing 0 */
         grpc_slice path_with_query_slice = grpc_slice_malloc(estimated_len);
 
@@ -320,8 +325,8 @@
         write_ptr++; /* for the '?' */
 
         grpc_base64_encode_core((char *)write_ptr, calld->payload_bytes,
-                                op->send_message->length, k_url_safe,
-                                k_multi_line);
+                                op->payload->send_message.send_message->length,
+                                k_url_safe, k_multi_line);
 
         /* remove trailing unused memory and add trailing 0 to terminate string
          */
@@ -335,14 +340,15 @@
         /* substitute previous path with the new path+query */
         grpc_mdelem mdelem_path_and_query = grpc_mdelem_from_slices(
             exec_ctx, GRPC_MDSTR_PATH, path_with_query_slice);
-        grpc_metadata_batch *b = op->send_initial_metadata;
+        grpc_metadata_batch *b =
+            op->payload->send_initial_metadata.send_initial_metadata;
         error = grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path,
                                                mdelem_path_and_query);
         if (error != GRPC_ERROR_NONE) return error;
 
         calld->on_complete = op->on_complete;
         op->on_complete = &calld->hc_on_complete;
-        op->send_message = NULL;
+        op->send_message = false;
         grpc_slice_unref_internal(exec_ctx, path_with_query_slice);
       } else {
         /* Not all data is available. Fall back to POST. */
@@ -353,47 +359,60 @@
       }
     }
 
-    remove_if_present(exec_ctx, op->send_initial_metadata, GRPC_BATCH_METHOD);
-    remove_if_present(exec_ctx, op->send_initial_metadata, GRPC_BATCH_SCHEME);
-    remove_if_present(exec_ctx, op->send_initial_metadata, GRPC_BATCH_TE);
-    remove_if_present(exec_ctx, op->send_initial_metadata,
+    remove_if_present(exec_ctx,
+                      op->payload->send_initial_metadata.send_initial_metadata,
+                      GRPC_BATCH_METHOD);
+    remove_if_present(exec_ctx,
+                      op->payload->send_initial_metadata.send_initial_metadata,
+                      GRPC_BATCH_SCHEME);
+    remove_if_present(exec_ctx,
+                      op->payload->send_initial_metadata.send_initial_metadata,
+                      GRPC_BATCH_TE);
+    remove_if_present(exec_ctx,
+                      op->payload->send_initial_metadata.send_initial_metadata,
                       GRPC_BATCH_CONTENT_TYPE);
-    remove_if_present(exec_ctx, op->send_initial_metadata,
+    remove_if_present(exec_ctx,
+                      op->payload->send_initial_metadata.send_initial_metadata,
                       GRPC_BATCH_USER_AGENT);
 
     /* Send : prefixed headers, which have to be before any application
        layer headers. */
-    error = grpc_metadata_batch_add_head(exec_ctx, op->send_initial_metadata,
-                                         &calld->method, method);
+    error = grpc_metadata_batch_add_head(
+        exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+        &calld->method, method);
     if (error != GRPC_ERROR_NONE) return error;
-    error =
-        grpc_metadata_batch_add_head(exec_ctx, op->send_initial_metadata,
-                                     &calld->scheme, channeld->static_scheme);
-    if (error != GRPC_ERROR_NONE) return error;
-    error = grpc_metadata_batch_add_tail(exec_ctx, op->send_initial_metadata,
-                                         &calld->te_trailers,
-                                         GRPC_MDELEM_TE_TRAILERS);
+    error = grpc_metadata_batch_add_head(
+        exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+        &calld->scheme, channeld->static_scheme);
     if (error != GRPC_ERROR_NONE) return error;
     error = grpc_metadata_batch_add_tail(
-        exec_ctx, op->send_initial_metadata, &calld->content_type,
-        GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
+        exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+        &calld->te_trailers, GRPC_MDELEM_TE_TRAILERS);
     if (error != GRPC_ERROR_NONE) return error;
-    error = grpc_metadata_batch_add_tail(exec_ctx, op->send_initial_metadata,
-                                         &calld->user_agent,
-                                         GRPC_MDELEM_REF(channeld->user_agent));
+    error = grpc_metadata_batch_add_tail(
+        exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+        &calld->content_type, GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
+    if (error != GRPC_ERROR_NONE) return error;
+    error = grpc_metadata_batch_add_tail(
+        exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+        &calld->user_agent, GRPC_MDELEM_REF(channeld->user_agent));
     if (error != GRPC_ERROR_NONE) return error;
   }
 
-  if (op->recv_initial_metadata != NULL) {
+  if (op->recv_initial_metadata) {
     /* substitute our callback for the higher callback */
-    calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = &calld->hc_on_recv_initial_metadata;
+    calld->recv_initial_metadata =
+        op->payload->recv_initial_metadata.recv_initial_metadata;
+    calld->on_done_recv_initial_metadata =
+        op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+    op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+        &calld->hc_on_recv_initial_metadata;
   }
 
-  if (op->recv_trailing_metadata != NULL) {
+  if (op->recv_trailing_metadata) {
     /* substitute our callback for the higher callback */
-    calld->recv_trailing_metadata = op->recv_trailing_metadata;
+    calld->recv_trailing_metadata =
+        op->payload->recv_trailing_metadata.recv_trailing_metadata;
     calld->on_done_recv_trailing_metadata = op->on_complete;
     op->on_complete = &calld->hc_on_recv_trailing_metadata;
   }
@@ -403,17 +422,17 @@
 
 static void hc_start_transport_op(grpc_exec_ctx *exec_ctx,
                                   grpc_call_element *elem,
-                                  grpc_transport_stream_op *op) {
+                                  grpc_transport_stream_op_batch *op) {
   GPR_TIMER_BEGIN("hc_start_transport_op", 0);
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
   grpc_error *error = hc_mutate_op(exec_ctx, elem, op);
   if (error != GRPC_ERROR_NONE) {
-    grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+    grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
   } else {
     call_data *calld = elem->call_data;
-    if (op->send_message != NULL && calld->send_message_blocked) {
+    if (op->send_message && calld->send_message_blocked) {
       /* Don't forward the op. send_message contains slices that aren't ready
-      yet. The call will be forwarded by the op_complete of slice read call.
+         yet. The call will be forwarded by the op_complete of slice read call.
       */
     } else {
       grpc_call_next_op(exec_ctx, elem, op);
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index df0f950..c1e49ff 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -58,8 +58,7 @@
   bool payload_bin_delivered;
 
   grpc_metadata_batch *recv_initial_metadata;
-  bool *recv_idempotent_request;
-  bool *recv_cacheable_request;
+  uint32_t *recv_initial_metadata_flags;
   /** Closure to call when finished with the hs_on_recv hook */
   grpc_closure *on_done_recv;
   /** Closure to call when we retrieve read message from the path URI
@@ -116,14 +115,21 @@
 
   if (b->idx.named.method != NULL) {
     if (grpc_mdelem_eq(b->idx.named.method->md, GRPC_MDELEM_METHOD_POST)) {
-      *calld->recv_idempotent_request = false;
-      *calld->recv_cacheable_request = false;
+      *calld->recv_initial_metadata_flags &=
+          ~(GRPC_INITIAL_METADATA_CACHEABLE_REQUEST |
+            GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST);
     } else if (grpc_mdelem_eq(b->idx.named.method->md,
                               GRPC_MDELEM_METHOD_PUT)) {
-      *calld->recv_idempotent_request = true;
+      *calld->recv_initial_metadata_flags &=
+          ~GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
+      *calld->recv_initial_metadata_flags |=
+          GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
     } else if (grpc_mdelem_eq(b->idx.named.method->md,
                               GRPC_MDELEM_METHOD_GET)) {
-      *calld->recv_cacheable_request = true;
+      *calld->recv_initial_metadata_flags |=
+          GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
+      *calld->recv_initial_metadata_flags &=
+          ~GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
     } else {
       add_error(error_name, &error,
                 grpc_attach_md_to_error(
@@ -206,7 +212,8 @@
               grpc_error_set_str(
                   GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"),
                   GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":path")));
-  } else if (*calld->recv_cacheable_request == true) {
+  } else if (*calld->recv_initial_metadata_flags &
+             GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) {
     /* We have a cacheable request made with GET verb. The path contains the
      * query parameter which is base64 encoded request payload. */
     const char k_query_separator = '?';
@@ -311,45 +318,53 @@
 }
 
 static void hs_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                         grpc_transport_stream_op *op) {
+                         grpc_transport_stream_op_batch *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
 
-  if (op->send_initial_metadata != NULL) {
+  if (op->send_initial_metadata) {
     grpc_error *error = GRPC_ERROR_NONE;
     static const char *error_name = "Failed sending initial metadata";
-    add_error(error_name, &error, grpc_metadata_batch_add_head(
-                                      exec_ctx, op->send_initial_metadata,
-                                      &calld->status, GRPC_MDELEM_STATUS_200));
+    add_error(
+        error_name, &error,
+        grpc_metadata_batch_add_head(
+            exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+            &calld->status, GRPC_MDELEM_STATUS_200));
+    add_error(
+        error_name, &error,
+        grpc_metadata_batch_add_tail(
+            exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+            &calld->content_type,
+            GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC));
     add_error(error_name, &error,
-              grpc_metadata_batch_add_tail(
-                  exec_ctx, op->send_initial_metadata, &calld->content_type,
-                  GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC));
-    add_error(error_name, &error,
-              server_filter_outgoing_metadata(exec_ctx, elem,
-                                              op->send_initial_metadata));
+              server_filter_outgoing_metadata(
+                  exec_ctx, elem,
+                  op->payload->send_initial_metadata.send_initial_metadata));
     if (error != GRPC_ERROR_NONE) {
-      grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+      grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
       return;
     }
   }
 
   if (op->recv_initial_metadata) {
     /* substitute our callback for the higher callback */
-    GPR_ASSERT(op->recv_idempotent_request != NULL);
-    GPR_ASSERT(op->recv_cacheable_request != NULL);
-    calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->recv_idempotent_request = op->recv_idempotent_request;
-    calld->recv_cacheable_request = op->recv_cacheable_request;
-    calld->on_done_recv = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = &calld->hs_on_recv;
+    GPR_ASSERT(op->payload->recv_initial_metadata.recv_flags != NULL);
+    calld->recv_initial_metadata =
+        op->payload->recv_initial_metadata.recv_initial_metadata;
+    calld->recv_initial_metadata_flags =
+        op->payload->recv_initial_metadata.recv_flags;
+    calld->on_done_recv =
+        op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+    op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+        &calld->hs_on_recv;
   }
 
   if (op->recv_message) {
-    calld->recv_message_ready = op->recv_message_ready;
-    calld->pp_recv_message = op->recv_message;
-    if (op->recv_message_ready) {
-      op->recv_message_ready = &calld->hs_recv_message_ready;
+    calld->recv_message_ready = op->payload->recv_message.recv_message_ready;
+    calld->pp_recv_message = op->payload->recv_message.recv_message;
+    if (op->payload->recv_message.recv_message_ready) {
+      op->payload->recv_message.recv_message_ready =
+          &calld->hs_recv_message_ready;
     }
     if (op->on_complete) {
       calld->on_complete = op->on_complete;
@@ -359,9 +374,10 @@
 
   if (op->send_trailing_metadata) {
     grpc_error *error = server_filter_outgoing_metadata(
-        exec_ctx, elem, op->send_trailing_metadata);
+        exec_ctx, elem,
+        op->payload->send_trailing_metadata.send_trailing_metadata);
     if (error != GRPC_ERROR_NONE) {
-      grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+      grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
       return;
     }
   }
@@ -369,7 +385,7 @@
 
 static void hs_start_transport_op(grpc_exec_ctx *exec_ctx,
                                   grpc_call_element *elem,
-                                  grpc_transport_stream_op *op) {
+                                  grpc_transport_stream_op_batch *op) {
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
   GPR_TIMER_BEGIN("hs_start_transport_op", 0);
   hs_mutate_op(exec_ctx, elem, op);
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c
index 6313665..57726c8 100644
--- a/src/core/lib/channel/message_size_filter.c
+++ b/src/core/lib/channel/message_size_filter.c
@@ -132,21 +132,23 @@
     gpr_free(message_string);
   }
   // Invoke the next callback.
-  grpc_closure_sched(exec_ctx, calld->next_recv_message_ready, error);
+  grpc_closure_run(exec_ctx, calld->next_recv_message_ready, error);
 }
 
 // Start transport stream op.
-static void start_transport_stream_op(grpc_exec_ctx* exec_ctx,
-                                      grpc_call_element* elem,
-                                      grpc_transport_stream_op* op) {
+static void start_transport_stream_op_batch(
+    grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
+    grpc_transport_stream_op_batch* op) {
   call_data* calld = elem->call_data;
   // Check max send message size.
-  if (op->send_message != NULL && calld->max_send_size >= 0 &&
-      op->send_message->length > (size_t)calld->max_send_size) {
+  if (op->send_message && calld->max_send_size >= 0 &&
+      op->payload->send_message.send_message->length >
+          (size_t)calld->max_send_size) {
     char* message_string;
     gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)",
-                 op->send_message->length, calld->max_send_size);
-    grpc_transport_stream_op_finish_with_failure(
+                 op->payload->send_message.send_message->length,
+                 calld->max_send_size);
+    grpc_transport_stream_op_batch_finish_with_failure(
         exec_ctx, op,
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string),
                            GRPC_ERROR_INT_GRPC_STATUS,
@@ -155,10 +157,11 @@
     return;
   }
   // Inject callback for receiving a message.
-  if (op->recv_message_ready != NULL) {
-    calld->next_recv_message_ready = op->recv_message_ready;
-    calld->recv_message = op->recv_message;
-    op->recv_message_ready = &calld->recv_message_ready;
+  if (op->recv_message) {
+    calld->next_recv_message_ready =
+        op->payload->recv_message.recv_message_ready;
+    calld->recv_message = op->payload->recv_message.recv_message;
+    op->payload->recv_message.recv_message_ready = &calld->recv_message_ready;
   }
   // Chain to the next filter.
   grpc_call_next_op(exec_ctx, elem, op);
@@ -253,7 +256,7 @@
 }
 
 const grpc_channel_filter grpc_message_size_filter = {
-    start_transport_stream_op,
+    start_transport_stream_op_batch,
     grpc_channel_next_op,
     sizeof(call_data),
     init_call_elem,
diff --git a/src/core/lib/iomgr/endpoint_pair.h b/src/core/lib/iomgr/endpoint_pair.h
index f9de0c7..6407a6a 100644
--- a/src/core/lib/iomgr/endpoint_pair.h
+++ b/src/core/lib/iomgr/endpoint_pair.h
@@ -41,8 +41,7 @@
   grpc_endpoint *server;
 } grpc_endpoint_pair;
 
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
-    const char *name, grpc_resource_quota *resource_quota,
-    size_t read_slice_size);
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
+                                                   grpc_channel_args *args);
 
 #endif /* GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H */
diff --git a/src/core/lib/iomgr/endpoint_pair_posix.c b/src/core/lib/iomgr/endpoint_pair_posix.c
index b9ff969..5542a37 100644
--- a/src/core/lib/iomgr/endpoint_pair_posix.c
+++ b/src/core/lib/iomgr/endpoint_pair_posix.c
@@ -62,22 +62,25 @@
   GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]) == GRPC_ERROR_NONE);
 }
 
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
-    const char *name, grpc_resource_quota *resource_quota,
-    size_t read_slice_size) {
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
+                                                   grpc_channel_args *args) {
   int sv[2];
   grpc_endpoint_pair p;
   char *final_name;
   create_sockets(sv);
 
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
   gpr_asprintf(&final_name, "%s:client", name);
-  p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), resource_quota,
-                             read_slice_size, "socketpair-server");
+  p.client = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], final_name), args,
+                             "socketpair-server");
   gpr_free(final_name);
   gpr_asprintf(&final_name, "%s:server", name);
-  p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), resource_quota,
-                             read_slice_size, "socketpair-client");
+  p.server = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[0], final_name), args,
+                             "socketpair-client");
   gpr_free(final_name);
+
+  grpc_exec_ctx_finish(&exec_ctx);
   return p;
 }
 
diff --git a/src/core/lib/iomgr/endpoint_pair_uv.c b/src/core/lib/iomgr/endpoint_pair_uv.c
index ff24894..9718eb0 100644
--- a/src/core/lib/iomgr/endpoint_pair_uv.c
+++ b/src/core/lib/iomgr/endpoint_pair_uv.c
@@ -41,9 +41,8 @@
 
 #include "src/core/lib/iomgr/endpoint_pair.h"
 
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
-    const char *name, grpc_resource_quota *resource_quota,
-    size_t read_slice_size) {
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
+                                                   grpc_channel_args *args) {
   grpc_endpoint_pair endpoint_pair;
   // TODO(mlumish): implement this properly under libuv
   GPR_ASSERT(false &&
diff --git a/src/core/lib/iomgr/endpoint_pair_windows.c b/src/core/lib/iomgr/endpoint_pair_windows.c
index 93f71b7..25d6264 100644
--- a/src/core/lib/iomgr/endpoint_pair_windows.c
+++ b/src/core/lib/iomgr/endpoint_pair_windows.c
@@ -83,15 +83,18 @@
 }
 
 grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
-    const char *name, grpc_resource_quota *resource_quota,
-    size_t read_slice_size) {
+    const char *name, grpc_channel_args *channel_args) {
   SOCKET sv[2];
   grpc_endpoint_pair p;
   create_sockets(sv);
-  p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"),
-                             resource_quota, "endpoint:server");
-  p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"),
-                             resource_quota, "endpoint:client");
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  p.client = grpc_tcp_create(&exec_ctx,
+                             grpc_winsocket_create(sv[1], "endpoint:client"),
+                             channel_args, "endpoint:server");
+  p.server = grpc_tcp_create(&exec_ctx,
+                             grpc_winsocket_create(sv[0], "endpoint:server"),
+                             channel_args, "endpoint:client");
+  grpc_exec_ctx_finish(&exec_ctx);
   return p;
 }
 
diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c
index 1dbb64e..fbbca6b 100644
--- a/src/core/lib/iomgr/error.c
+++ b/src/core/lib/iomgr/error.c
@@ -212,7 +212,11 @@
   GPR_ASSERT(*err);
   uint8_t slots = (uint8_t)(size / sizeof(intptr_t));
   if ((*err)->arena_size + slots > (*err)->arena_capacity) {
-    (*err)->arena_capacity = (uint8_t)(3 * (*err)->arena_capacity / 2);
+    (*err)->arena_capacity =
+        (uint8_t)GPR_MIN(UINT8_MAX - 1, (3 * (*err)->arena_capacity / 2));
+    if ((*err)->arena_size + slots > (*err)->arena_capacity) {
+      return UINT8_MAX;
+    }
     *err = gpr_realloc(
         *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t));
   }
@@ -223,10 +227,14 @@
 
 static void internal_set_int(grpc_error **err, grpc_error_ints which,
                              intptr_t value) {
-  // GPR_ASSERT((*err)->ints[which] == UINT8_MAX); // TODO, enforce this
   uint8_t slot = (*err)->ints[which];
   if (slot == UINT8_MAX) {
     slot = get_placement(err, sizeof(value));
+    if (slot == UINT8_MAX) {
+      gpr_log(GPR_ERROR, "Error %p is full, dropping int {\"%s\":%" PRIiPTR "}",
+              *err, error_int_name(which), value);
+      return;
+    }
   }
   (*err)->ints[which] = slot;
   (*err)->arena[slot] = value;
@@ -234,10 +242,16 @@
 
 static void internal_set_str(grpc_error **err, grpc_error_strs which,
                              grpc_slice value) {
-  // GPR_ASSERT((*err)->strs[which] == UINT8_MAX); // TODO, enforce this
   uint8_t slot = (*err)->strs[which];
   if (slot == UINT8_MAX) {
     slot = get_placement(err, sizeof(value));
+    if (slot == UINT8_MAX) {
+      const char *str = grpc_slice_to_c_string(value);
+      gpr_log(GPR_ERROR, "Error %p is full, dropping string {\"%s\":\"%s\"}",
+              *err, error_str_name(which), str);
+      gpr_free((void *)str);
+      return;
+    }
   } else {
     unref_slice(*(grpc_slice *)((*err)->arena + slot));
   }
@@ -245,12 +259,19 @@
   memcpy((*err)->arena + slot, &value, sizeof(value));
 }
 
+static char *fmt_time(gpr_timespec tm);
 static void internal_set_time(grpc_error **err, grpc_error_times which,
                               gpr_timespec value) {
-  // GPR_ASSERT((*err)->times[which] == UINT8_MAX); // TODO, enforce this
   uint8_t slot = (*err)->times[which];
   if (slot == UINT8_MAX) {
     slot = get_placement(err, sizeof(value));
+    if (slot == UINT8_MAX) {
+      const char *time_str = fmt_time(value);
+      gpr_log(GPR_ERROR, "Error %p is full, dropping \"%s\":\"%s\"}", *err,
+              error_time_name(which), time_str);
+      gpr_free((void *)time_str);
+      return;
+    }
   }
   (*err)->times[which] = slot;
   memcpy((*err)->arena + slot, &value, sizeof(value));
@@ -259,6 +280,12 @@
 static void internal_add_error(grpc_error **err, grpc_error *new) {
   grpc_linked_error new_last = {new, UINT8_MAX};
   uint8_t slot = get_placement(err, sizeof(grpc_linked_error));
+  if (slot == UINT8_MAX) {
+    gpr_log(GPR_ERROR, "Error %p is full, dropping error %p = %s", *err, new,
+            grpc_error_string(new));
+    GRPC_ERROR_UNREF(new);
+    return;
+  }
   if ((*err)->first_err == UINT8_MAX) {
     GPR_ASSERT((*err)->last_err == UINT8_MAX);
     (*err)->last_err = slot;
diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c
index f6372c0..e5cf54f 100644
--- a/src/core/lib/iomgr/ev_epoll_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_linux.c
@@ -56,6 +56,7 @@
 
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/iomgr/workqueue.h"
 #include "src/core/lib/profiling/timers.h"
@@ -1467,8 +1468,9 @@
     return 0;
   }
   timeout = gpr_time_sub(deadline, now);
-  return gpr_time_to_millis(gpr_time_add(
+  int millis = gpr_time_to_millis(gpr_time_add(
       timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN)));
+  return millis >= 1 ? millis : 1;
 }
 
 static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
@@ -1650,6 +1652,7 @@
     for (int i = 0; i < ep_rv; ++i) {
       void *data_ptr = ep_ev[i].data.ptr;
       if (data_ptr == &global_wakeup_fd) {
+        grpc_timer_consume_kick();
         append_error(error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
                      err_desc);
       } else if (data_ptr == &pi->workqueue_wakeup_fd) {
@@ -1714,7 +1717,7 @@
   worker.pt_id = pthread_self();
   gpr_atm_no_barrier_store(&worker.is_kicked, (gpr_atm)0);
 
-  *worker_hdl = &worker;
+  if (worker_hdl) *worker_hdl = &worker;
 
   gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset);
   gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
@@ -1792,7 +1795,7 @@
     gpr_mu_lock(&pollset->po.mu);
   }
 
-  *worker_hdl = NULL;
+  if (worker_hdl) *worker_hdl = NULL;
 
   gpr_tls_set(&g_current_thread_pollset, (intptr_t)0);
   gpr_tls_set(&g_current_thread_worker, (intptr_t)0);
diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c
index ca6e855..9834cdd 100644
--- a/src/core/lib/iomgr/ev_poll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_posix.c
@@ -52,6 +52,7 @@
 #include <grpc/support/useful.h>
 
 #include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/iomgr/wakeup_fd_cv.h"
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/profiling/timers.h"
@@ -870,7 +871,7 @@
                                 grpc_pollset_worker **worker_hdl,
                                 gpr_timespec now, gpr_timespec deadline) {
   grpc_pollset_worker worker;
-  *worker_hdl = &worker;
+  if (worker_hdl) *worker_hdl = &worker;
   grpc_error *error = GRPC_ERROR_NONE;
 
   /* Avoid malloc for small number of elements. */
@@ -1006,6 +1007,7 @@
         }
       } else {
         if (pfds[0].revents & POLLIN_CHECK) {
+          grpc_timer_consume_kick();
           work_combine_error(&error,
                              grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd));
         }
@@ -1090,7 +1092,7 @@
       gpr_mu_lock(&pollset->mu);
     }
   }
-  *worker_hdl = NULL;
+  if (worker_hdl) *worker_hdl = NULL;
   GPR_TIMER_END("pollset_work", 0);
   GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error));
   return error;
diff --git a/src/core/lib/iomgr/ev_posix.c b/src/core/lib/iomgr/ev_posix.c
index b5be550..13409a4 100644
--- a/src/core/lib/iomgr/ev_posix.c
+++ b/src/core/lib/iomgr/ev_posix.c
@@ -111,6 +111,12 @@
   }
 }
 
+/* This should be used for testing purposes ONLY */
+void grpc_set_event_engine_test_only(
+    const grpc_event_engine_vtable *ev_engine) {
+  g_event_engine = ev_engine;
+}
+
 /* Call this only after calling grpc_event_engine_init() */
 const char *grpc_get_poll_strategy_name() { return g_poll_strategy_name; }
 
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index 1a9e5c1..becc4d3 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -183,4 +183,7 @@
 typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int);
 extern grpc_poll_function_type grpc_poll_function;
 
+/* This should be used for testing purposes ONLY */
+void grpc_set_event_engine_test_only(const grpc_event_engine_vtable *);
+
 #endif /* GRPC_CORE_LIB_IOMGR_EV_POSIX_H */
diff --git a/src/core/lib/iomgr/pollset.h b/src/core/lib/iomgr/pollset.h
index e19ce69..9bf3cda 100644
--- a/src/core/lib/iomgr/pollset.h
+++ b/src/core/lib/iomgr/pollset.h
@@ -75,6 +75,10 @@
    and it is guaranteed that it will not be released by grpc_pollset_work
    AFTER worker has been destroyed.
 
+   It's legal for worker to be NULL: in that case, this specific thread can not
+   be directly woken with a kick, but maybe be indirectly (with a kick against
+   the pollset as a whole).
+
    Tries not to block past deadline.
    May call grpc_closure_list_run on grpc_closure_list, without holding the
    pollset
diff --git a/src/core/lib/iomgr/pollset_windows.c b/src/core/lib/iomgr/pollset_windows.c
index 17043c1..04c6b71 100644
--- a/src/core/lib/iomgr/pollset_windows.c
+++ b/src/core/lib/iomgr/pollset_windows.c
@@ -120,7 +120,7 @@
                               grpc_pollset_worker **worker_hdl,
                               gpr_timespec now, gpr_timespec deadline) {
   grpc_pollset_worker worker;
-  *worker_hdl = &worker;
+  if (worker_hdl) *worker_hdl = &worker;
 
   int added_worker = 0;
   worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next =
@@ -185,7 +185,7 @@
     remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_POLLSET);
   }
   gpr_cv_destroy(&worker.cv);
-  *worker_hdl = NULL;
+  if (worker_hdl) *worker_hdl = NULL;
   return GRPC_ERROR_NONE;
 }
 
diff --git a/src/core/lib/iomgr/resource_quota.c b/src/core/lib/iomgr/resource_quota.c
index 8dcd80d..c3ee878 100644
--- a/src/core/lib/iomgr/resource_quota.c
+++ b/src/core/lib/iomgr/resource_quota.c
@@ -142,6 +142,8 @@
   /* Amount of free memory in the resource quota */
   int64_t free_pool;
 
+  gpr_atm last_size;
+
   /* Has rq_step been scheduled to occur? */
   bool step_scheduled;
   /* Are we currently reclaiming memory */
@@ -581,6 +583,7 @@
   resource_quota->combiner = grpc_combiner_create(NULL);
   resource_quota->free_pool = INT64_MAX;
   resource_quota->size = INT64_MAX;
+  gpr_atm_no_barrier_store(&resource_quota->last_size, GPR_ATM_MAX);
   resource_quota->step_scheduled = false;
   resource_quota->reclaiming = false;
   gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation, 0);
@@ -643,11 +646,17 @@
   rq_resize_args *a = gpr_malloc(sizeof(*a));
   a->resource_quota = grpc_resource_quota_ref_internal(resource_quota);
   a->size = (int64_t)size;
+  gpr_atm_no_barrier_store(&resource_quota->last_size,
+                           (gpr_atm)GPR_MIN((size_t)GPR_ATM_MAX, size));
   grpc_closure_init(&a->closure, rq_resize, a, grpc_schedule_on_exec_ctx);
   grpc_closure_sched(&exec_ctx, &a->closure, GRPC_ERROR_NONE);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
+size_t grpc_resource_quota_peek_size(grpc_resource_quota *resource_quota) {
+  return (size_t)gpr_atm_no_barrier_load(&resource_quota->last_size);
+}
+
 /*******************************************************************************
  * grpc_resource_user channel args api
  */
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
index b9f62cb..6f99be0 100644
--- a/src/core/lib/iomgr/resource_quota.h
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -90,6 +90,8 @@
 double grpc_resource_quota_get_memory_pressure(
     grpc_resource_quota *resource_quota);
 
+size_t grpc_resource_quota_peek_size(grpc_resource_quota *resource_quota);
+
 typedef struct grpc_resource_user grpc_resource_user;
 
 grpc_resource_user *grpc_resource_user_create(
diff --git a/src/core/lib/iomgr/tcp_client.h b/src/core/lib/iomgr/tcp_client.h
index 0485661..bc367bd 100644
--- a/src/core/lib/iomgr/tcp_client.h
+++ b/src/core/lib/iomgr/tcp_client.h
@@ -40,10 +40,6 @@
 #include "src/core/lib/iomgr/pollset_set.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
-/* Channel arg (integer) setting how large a slice to try and read from the wire
-   each time recvmsg (or equivalent) is called */
-#define GRPC_ARG_TCP_READ_CHUNK_SIZE "grpc.experimental.tcp_read_chunk_size"
-
 /* Asynchronously connect to an address (specified as (addr, len)), and call
    cb with arg and the completed connection when done (or call cb with arg and
    NULL on failure).
diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c
index a108b10..a269270 100644
--- a/src/core/lib/iomgr/tcp_client_posix.c
+++ b/src/core/lib/iomgr/tcp_client_posix.c
@@ -137,29 +137,7 @@
 grpc_endpoint *grpc_tcp_client_create_from_fd(
     grpc_exec_ctx *exec_ctx, grpc_fd *fd, const grpc_channel_args *channel_args,
     const char *addr_str) {
-  size_t tcp_read_chunk_size = GRPC_TCP_DEFAULT_READ_SLICE_SIZE;
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
-  if (channel_args != NULL) {
-    for (size_t i = 0; i < channel_args->num_args; i++) {
-      if (0 ==
-          strcmp(channel_args->args[i].key, GRPC_ARG_TCP_READ_CHUNK_SIZE)) {
-        grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
-                                        8 * 1024 * 1024};
-        tcp_read_chunk_size = (size_t)grpc_channel_arg_get_integer(
-            &channel_args->args[i], options);
-      } else if (0 ==
-                 strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
-        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
-        resource_quota = grpc_resource_quota_ref_internal(
-            channel_args->args[i].value.pointer.p);
-      }
-    }
-  }
-
-  grpc_endpoint *ep =
-      grpc_tcp_create(fd, resource_quota, tcp_read_chunk_size, addr_str);
-  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
-  return ep;
+  return grpc_tcp_create(exec_ctx, fd, channel_args, addr_str);
 }
 
 static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
diff --git a/src/core/lib/iomgr/tcp_client_windows.c b/src/core/lib/iomgr/tcp_client_windows.c
index a356564..d6baca5 100644
--- a/src/core/lib/iomgr/tcp_client_windows.c
+++ b/src/core/lib/iomgr/tcp_client_windows.c
@@ -63,7 +63,7 @@
   int refs;
   grpc_closure on_connect;
   grpc_endpoint **endpoint;
-  grpc_resource_quota *resource_quota;
+  grpc_channel_args *channel_args;
 } async_connect;
 
 static void async_connect_unlock_and_cleanup(grpc_exec_ctx *exec_ctx,
@@ -72,7 +72,7 @@
   int done = (--ac->refs == 0);
   gpr_mu_unlock(&ac->mu);
   if (done) {
-    grpc_resource_quota_unref_internal(exec_ctx, ac->resource_quota);
+    grpc_channel_args_destroy(exec_ctx, ac->channel_args);
     gpr_mu_destroy(&ac->mu);
     gpr_free(ac->addr_name);
     gpr_free(ac);
@@ -119,7 +119,8 @@
       if (!wsa_success) {
         error = GRPC_WSA_ERROR(WSAGetLastError(), "ConnectEx");
       } else {
-        *ep = grpc_tcp_create(socket, ac->resource_quota, ac->addr_name);
+        *ep =
+            grpc_tcp_create(exec_ctx, socket, ac->channel_args, ac->addr_name);
         socket = NULL;
       }
     } else {
@@ -152,17 +153,6 @@
   grpc_winsocket_callback_info *info;
   grpc_error *error = GRPC_ERROR_NONE;
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
-  if (channel_args != NULL) {
-    for (size_t i = 0; i < channel_args->num_args; i++) {
-      if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
-        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
-        resource_quota = grpc_resource_quota_ref_internal(
-            channel_args->args[i].value.pointer.p);
-      }
-    }
-  }
-
   *endpoint = NULL;
 
   /* Use dualstack sockets where available. */
@@ -225,7 +215,7 @@
   ac->refs = 2;
   ac->addr_name = grpc_sockaddr_to_uri(addr);
   ac->endpoint = endpoint;
-  ac->resource_quota = resource_quota;
+  ac->channel_args = grpc_channel_args_copy(channel_args);
   grpc_closure_init(&ac->on_connect, on_connect, ac, grpc_schedule_on_exec_ctx);
 
   grpc_closure_init(&ac->on_alarm, on_alarm, ac, grpc_schedule_on_exec_ctx);
@@ -247,7 +237,6 @@
   } else if (sock != INVALID_SOCKET) {
     closesocket(sock);
   }
-  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
   grpc_closure_sched(exec_ctx, on_done, final_error);
 }
 
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index 4d7cf3f..5f4b38d 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -52,7 +52,9 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
+#include <grpc/support/useful.h>
 
+#include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/profiling/timers.h"
@@ -80,10 +82,14 @@
   int fd;
   bool finished_edge;
   msg_iovlen_type iov_size; /* Number of slices to allocate per read attempt */
-  size_t slice_size;
+  double target_length;
+  double bytes_read_this_round;
   gpr_refcount refcount;
   gpr_atm shutdown_count;
 
+  int min_read_chunk_size;
+  int max_read_chunk_size;
+
   /* garbage after the last read */
   grpc_slice_buffer last_read_buffer;
 
@@ -108,6 +114,42 @@
   grpc_resource_user_slice_allocator slice_allocator;
 } grpc_tcp;
 
+static void add_to_estimate(grpc_tcp *tcp, size_t bytes) {
+  tcp->bytes_read_this_round += (double)bytes;
+}
+
+static void finish_estimate(grpc_tcp *tcp) {
+  /* If we read >80% of the target buffer in one read loop, increase the size
+     of the target buffer to either the amount read, or twice its previous
+     value */
+  if (tcp->bytes_read_this_round > tcp->target_length * 0.8) {
+    tcp->target_length =
+        GPR_MAX(2 * tcp->target_length, tcp->bytes_read_this_round);
+  } else {
+    tcp->target_length =
+        0.99 * tcp->target_length + 0.01 * tcp->bytes_read_this_round;
+  }
+  tcp->bytes_read_this_round = 0;
+}
+
+static size_t get_target_read_size(grpc_tcp *tcp) {
+  grpc_resource_quota *rq = grpc_resource_user_quota(tcp->resource_user);
+  double pressure = grpc_resource_quota_get_memory_pressure(rq);
+  double target =
+      tcp->target_length * (pressure > 0.8 ? (1.0 - pressure) / 0.2 : 1.0);
+  size_t sz = (((size_t)GPR_CLAMP(target, tcp->min_read_chunk_size,
+                                  tcp->max_read_chunk_size)) +
+               255) &
+              ~(size_t)255;
+  /* don't use more than 1/16th of the overall resource quota for a single read
+   * alloc */
+  size_t rqmax = grpc_resource_quota_peek_size(rq);
+  if (sz > rqmax / 16 && rqmax > 1024) {
+    sz = rqmax / 16;
+  }
+  return sz;
+}
+
 static grpc_error *tcp_annotate_error(grpc_error *src_error, grpc_tcp *tcp) {
   return grpc_error_set_str(
       grpc_error_set_int(src_error, GRPC_ERROR_INT_FD, tcp->fd),
@@ -232,9 +274,7 @@
     /* NB: After calling call_read_cb a parallel call of the read handler may
      * be running. */
     if (errno == EAGAIN) {
-      if (tcp->iov_size > 1) {
-        tcp->iov_size /= 2;
-      }
+      finish_estimate(tcp);
       /* We've consumed the edge, request a new one */
       grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
     } else {
@@ -253,14 +293,13 @@
             GRPC_ERROR_CREATE_FROM_STATIC_STRING("Socket closed"), tcp));
     TCP_UNREF(exec_ctx, tcp, "read");
   } else {
+    add_to_estimate(tcp, (size_t)read_bytes);
     GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
     if ((size_t)read_bytes < tcp->incoming_buffer->length) {
       grpc_slice_buffer_trim_end(
           tcp->incoming_buffer,
           tcp->incoming_buffer->length - (size_t)read_bytes,
           &tcp->last_read_buffer);
-    } else if (tcp->iov_size < MAX_READ_IOVEC) {
-      ++tcp->iov_size;
     }
     GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length);
     call_read_cb(exec_ctx, tcp, GRPC_ERROR_NONE);
@@ -285,11 +324,11 @@
 }
 
 static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
-  if (tcp->incoming_buffer->count < (size_t)tcp->iov_size) {
-    grpc_resource_user_alloc_slices(
-        exec_ctx, &tcp->slice_allocator, tcp->slice_size,
-        (size_t)tcp->iov_size - tcp->incoming_buffer->count,
-        tcp->incoming_buffer);
+  size_t target_read_size = get_target_read_size(tcp);
+  if (tcp->incoming_buffer->length < target_read_size &&
+      tcp->incoming_buffer->count < MAX_READ_IOVEC) {
+    grpc_resource_user_alloc_slices(exec_ctx, &tcp->slice_allocator,
+                                    target_read_size, 1, tcp->incoming_buffer);
   } else {
     tcp_do_read(exec_ctx, tcp);
   }
@@ -540,9 +579,50 @@
                                             tcp_get_peer,
                                             tcp_get_fd};
 
-grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
-                               grpc_resource_quota *resource_quota,
-                               size_t slice_size, const char *peer_string) {
+#define MAX_CHUNK_SIZE 32 * 1024 * 1024
+
+grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_fd *em_fd,
+                               const grpc_channel_args *channel_args,
+                               const char *peer_string) {
+  int tcp_read_chunk_size = GRPC_TCP_DEFAULT_READ_SLICE_SIZE;
+  int tcp_max_read_chunk_size = 4 * 1024 * 1024;
+  int tcp_min_read_chunk_size = 256;
+  grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
+  if (channel_args != NULL) {
+    for (size_t i = 0; i < channel_args->num_args; i++) {
+      if (0 ==
+          strcmp(channel_args->args[i].key, GRPC_ARG_TCP_READ_CHUNK_SIZE)) {
+        grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
+                                        MAX_CHUNK_SIZE};
+        tcp_read_chunk_size =
+            grpc_channel_arg_get_integer(&channel_args->args[i], options);
+      } else if (0 == strcmp(channel_args->args[i].key,
+                             GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE)) {
+        grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
+                                        MAX_CHUNK_SIZE};
+        tcp_min_read_chunk_size =
+            grpc_channel_arg_get_integer(&channel_args->args[i], options);
+      } else if (0 == strcmp(channel_args->args[i].key,
+                             GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE)) {
+        grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
+                                        MAX_CHUNK_SIZE};
+        tcp_max_read_chunk_size =
+            grpc_channel_arg_get_integer(&channel_args->args[i], options);
+      } else if (0 ==
+                 strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
+        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
+        resource_quota = grpc_resource_quota_ref_internal(
+            channel_args->args[i].value.pointer.p);
+      }
+    }
+  }
+
+  if (tcp_min_read_chunk_size > tcp_max_read_chunk_size) {
+    tcp_min_read_chunk_size = tcp_max_read_chunk_size;
+  }
+  tcp_read_chunk_size = GPR_CLAMP(tcp_read_chunk_size, tcp_min_read_chunk_size,
+                                  tcp_max_read_chunk_size);
+
   grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
   tcp->base.vtable = &vtable;
   tcp->peer_string = gpr_strdup(peer_string);
@@ -552,7 +632,10 @@
   tcp->release_fd_cb = NULL;
   tcp->release_fd = NULL;
   tcp->incoming_buffer = NULL;
-  tcp->slice_size = slice_size;
+  tcp->target_length = (double)tcp_read_chunk_size;
+  tcp->min_read_chunk_size = tcp_min_read_chunk_size;
+  tcp->max_read_chunk_size = tcp_max_read_chunk_size;
+  tcp->bytes_read_this_round = 0;
   tcp->iov_size = 1;
   tcp->finished_edge = true;
   /* paired with unref in grpc_tcp_destroy */
@@ -569,6 +652,7 @@
       &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);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
 
   return &tcp->base;
 }
diff --git a/src/core/lib/iomgr/tcp_posix.h b/src/core/lib/iomgr/tcp_posix.h
index 1c0d13f..1ad5788 100644
--- a/src/core/lib/iomgr/tcp_posix.h
+++ b/src/core/lib/iomgr/tcp_posix.h
@@ -47,14 +47,13 @@
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 
-#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
-
 extern int grpc_tcp_trace;
 
 /* Create a tcp endpoint given a file desciptor and a read slice size.
    Takes ownership of fd. */
-grpc_endpoint *grpc_tcp_create(grpc_fd *fd, grpc_resource_quota *resource_quota,
-                               size_t read_slice_size, const char *peer_string);
+grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
+                               const grpc_channel_args *args,
+                               const char *peer_string);
 
 /* Return the tcp endpoint's fd, or -1 if this is not available. Does not
    release the fd.
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
index d6a017c..e66ffc9 100644
--- a/src/core/lib/iomgr/tcp_server_posix.c
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -59,6 +59,7 @@
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
@@ -90,7 +91,6 @@
 
   grpc_tcp_server *s = gpr_zalloc(sizeof(grpc_tcp_server));
   s->so_reuseport = has_so_reuseport;
-  s->resource_quota = grpc_resource_quota_create(NULL);
   s->expand_wildcard_addrs = false;
   for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
     if (0 == strcmp(GRPC_ARG_ALLOW_REUSEPORT, args->args[i].key)) {
@@ -98,27 +98,14 @@
         s->so_reuseport =
             has_so_reuseport && (args->args[i].value.integer != 0);
       } else {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
         gpr_free(s);
         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(GRPC_ARG_ALLOW_REUSEPORT
                                                     " must be an integer");
       }
-    } else if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
-      if (args->args[i].type == GRPC_ARG_POINTER) {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
-        s->resource_quota =
-            grpc_resource_quota_ref_internal(args->args[i].value.pointer.p);
-      } else {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
-        gpr_free(s);
-        return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool");
-      }
     } else if (0 == strcmp(GRPC_ARG_EXPAND_WILDCARD_ADDRS, args->args[i].key)) {
       if (args->args[i].type == GRPC_ARG_INTEGER) {
         s->expand_wildcard_addrs = (args->args[i].value.integer != 0);
       } else {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
         gpr_free(s);
         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
             GRPC_ARG_EXPAND_WILDCARD_ADDRS " must be an integer");
@@ -138,6 +125,7 @@
   s->head = NULL;
   s->tail = NULL;
   s->nports = 0;
+  s->channel_args = grpc_channel_args_copy(args);
   gpr_atm_no_barrier_store(&s->next_pollset_to_assign, 0);
   *server = s;
   return GRPC_ERROR_NONE;
@@ -158,8 +146,7 @@
     s->head = sp->next;
     gpr_free(sp);
   }
-
-  grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
+  grpc_channel_args_destroy(exec_ctx, s->channel_args);
 
   gpr_free(s);
 }
@@ -286,8 +273,7 @@
 
     sp->server->on_accept_cb(
         exec_ctx, sp->server->on_accept_cb_arg,
-        grpc_tcp_create(fdobj, sp->server->resource_quota,
-                        GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str),
+        grpc_tcp_create(exec_ctx, fdobj, sp->server->channel_args, addr_str),
         read_notifier_pollset, acceptor);
 
     gpr_free(name);
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix.h b/src/core/lib/iomgr/tcp_server_utils_posix.h
index f5dc853..c15e2e1 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix.h
+++ b/src/core/lib/iomgr/tcp_server_utils_posix.h
@@ -103,7 +103,8 @@
   /* next pollset to assign a channel to */
   gpr_atm next_pollset_to_assign;
 
-  grpc_resource_quota *resource_quota;
+  /* channel args for this server */
+  grpc_channel_args *channel_args;
 };
 
 /* If successful, add a listener to \a s for \a addr, set \a dsmode for the
diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c
index 12ce7d3..4c17f08 100644
--- a/src/core/lib/iomgr/tcp_server_windows.c
+++ b/src/core/lib/iomgr/tcp_server_windows.c
@@ -46,6 +46,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/pollset_windows.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -102,7 +103,7 @@
   /* shutdown callback */
   grpc_closure *shutdown_complete;
 
-  grpc_resource_quota *resource_quota;
+  grpc_channel_args *channel_args;
 };
 
 /* Public function. Allocates the proper data structures to hold a
@@ -112,21 +113,7 @@
                                    const grpc_channel_args *args,
                                    grpc_tcp_server **server) {
   grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
-  s->resource_quota = grpc_resource_quota_create(NULL);
-  for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
-    if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
-      if (args->args[i].type == GRPC_ARG_POINTER) {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
-        s->resource_quota =
-            grpc_resource_quota_ref_internal(args->args[i].value.pointer.p);
-      } else {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
-        gpr_free(s);
-        return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool");
-      }
-    }
-  }
+  s->channel_args = grpc_channel_args_copy(args);
   gpr_ref_init(&s->refs, 1);
   gpr_mu_init(&s->mu);
   s->active_ports = 0;
@@ -155,7 +142,7 @@
     grpc_winsocket_destroy(sp->socket);
     gpr_free(sp);
   }
-  grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
+  grpc_channel_args_destroy(exec_ctx, s->channel_args);
   gpr_free(s);
 }
 
@@ -383,8 +370,8 @@
         gpr_free(utf8_message);
       }
       gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string);
-      ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name),
-                           sp->server->resource_quota, peer_name_string);
+      ep = grpc_tcp_create(exec_ctx, grpc_winsocket_create(sock, fd_name),
+                           sp->server->channel_args, peer_name_string);
       gpr_free(fd_name);
       gpr_free(peer_name_string);
     } else {
diff --git a/src/core/lib/iomgr/tcp_windows.c b/src/core/lib/iomgr/tcp_windows.c
index 9134883..f74aa68 100644
--- a/src/core/lib/iomgr/tcp_windows.c
+++ b/src/core/lib/iomgr/tcp_windows.c
@@ -430,9 +430,19 @@
                                       win_get_peer,
                                       win_get_fd};
 
-grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket,
-                               grpc_resource_quota *resource_quota,
+grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
+                               grpc_channel_args *channel_args,
                                char *peer_string) {
+  grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
+  if (channel_args != NULL) {
+    for (size_t i = 0; i < channel_args->num_args; i++) {
+      if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
+        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
+        resource_quota = grpc_resource_quota_ref_internal(
+            channel_args->args[i].value.pointer.p);
+      }
+    }
+  }
   grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
   memset(tcp, 0, sizeof(grpc_tcp));
   tcp->base.vtable = &vtable;
diff --git a/src/core/lib/iomgr/tcp_windows.h b/src/core/lib/iomgr/tcp_windows.h
index 4402de1..abafdb2 100644
--- a/src/core/lib/iomgr/tcp_windows.h
+++ b/src/core/lib/iomgr/tcp_windows.h
@@ -50,8 +50,8 @@
 /* Create a tcp endpoint given a winsock handle.
  * Takes ownership of the handle.
  */
-grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket,
-                               grpc_resource_quota *resource_quota,
+grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
+                               grpc_channel_args *channel_args,
                                char *peer_string);
 
 grpc_error *grpc_tcp_prepare_socket(SOCKET sock);
diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h
index d84a278..e0338f9 100644
--- a/src/core/lib/iomgr/timer.h
+++ b/src/core/lib/iomgr/timer.h
@@ -101,6 +101,9 @@
 void grpc_timer_list_init(gpr_timespec now);
 void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx);
 
+/* Consume a kick issued by grpc_kick_poller */
+void grpc_timer_consume_kick(void);
+
 /* the following must be implemented by each iomgr implementation */
 
 void grpc_kick_poller(void);
diff --git a/src/core/lib/iomgr/timer_generic.c b/src/core/lib/iomgr/timer_generic.c
index e53c801..d8e6068 100644
--- a/src/core/lib/iomgr/timer_generic.c
+++ b/src/core/lib/iomgr/timer_generic.c
@@ -37,9 +37,13 @@
 
 #include "src/core/lib/iomgr/timer.h"
 
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
+#include <grpc/support/tls.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/time_averaged_stats.h"
 #include "src/core/lib/iomgr/timer_heap.h"
 #include "src/core/lib/support/spinlock.h"
@@ -52,12 +56,15 @@
 #define MIN_QUEUE_WINDOW_DURATION 0.01
 #define MAX_QUEUE_WINDOW_DURATION 1
 
+int grpc_timer_trace = 0;
+int grpc_timer_check_trace = 0;
+
 typedef struct {
   gpr_mu mu;
   grpc_time_averaged_stats stats;
   /* All and only timers with deadlines <= this will be in the heap. */
-  gpr_timespec queue_deadline_cap;
-  gpr_timespec min_deadline;
+  gpr_atm queue_deadline_cap;
+  gpr_atm min_deadline;
   /* Index in the g_shard_queue */
   uint32_t shard_queue_index;
   /* This holds all timers with deadlines < queue_deadline_cap. Timers in this
@@ -67,38 +74,92 @@
   grpc_timer list;
 } shard_type;
 
-/* Protects g_shard_queue */
-static gpr_mu g_mu;
-/* Allow only one run_some_expired_timers at once */
-static gpr_spinlock g_checker_mu = GPR_SPINLOCK_STATIC_INITIALIZER;
+struct shared_mutables {
+  gpr_atm min_timer;
+  /* Allow only one run_some_expired_timers at once */
+  gpr_spinlock checker_mu;
+  bool initialized;
+  /* Protects g_shard_queue */
+  gpr_mu mu;
+} GPR_ALIGN_STRUCT(GPR_CACHELINE_SIZE);
+
+static struct shared_mutables g_shared_mutables = {
+    .checker_mu = GPR_SPINLOCK_STATIC_INITIALIZER, .initialized = false,
+};
 static gpr_clock_type g_clock_type;
 static shard_type g_shards[NUM_SHARDS];
-/* Protected by g_mu */
+/* Protected by g_shared_mutables.mu */
 static shard_type *g_shard_queue[NUM_SHARDS];
-static bool g_initialized = false;
+static gpr_timespec g_start_time;
 
-static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
-                                   gpr_timespec *next, grpc_error *error);
+GPR_TLS_DECL(g_last_seen_min_timer);
 
-static gpr_timespec compute_min_deadline(shard_type *shard) {
+static gpr_atm saturating_add(gpr_atm a, gpr_atm b) {
+  if (a > GPR_ATM_MAX - b) {
+    return GPR_ATM_MAX;
+  }
+  return a + b;
+}
+
+static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_atm now,
+                                   gpr_atm *next, grpc_error *error);
+
+static gpr_timespec dbl_to_ts(double d) {
+  gpr_timespec ts;
+  ts.tv_sec = (int64_t)d;
+  ts.tv_nsec = (int32_t)(1e9 * (d - (double)ts.tv_sec));
+  ts.clock_type = GPR_TIMESPAN;
+  return ts;
+}
+
+static gpr_atm timespec_to_atm_round_up(gpr_timespec ts) {
+  ts = gpr_time_sub(ts, g_start_time);
+  double x = GPR_MS_PER_SEC * (double)ts.tv_sec +
+             (double)ts.tv_nsec / GPR_NS_PER_MS +
+             (double)(GPR_NS_PER_SEC - 1) / (double)GPR_NS_PER_SEC;
+  if (x < 0) return 0;
+  if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
+  return (gpr_atm)x;
+}
+
+static gpr_atm timespec_to_atm_round_down(gpr_timespec ts) {
+  ts = gpr_time_sub(ts, g_start_time);
+  double x =
+      GPR_MS_PER_SEC * (double)ts.tv_sec + (double)ts.tv_nsec / GPR_NS_PER_MS;
+  if (x < 0) return 0;
+  if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
+  return (gpr_atm)x;
+}
+
+static gpr_timespec atm_to_timespec(gpr_atm x) {
+  return gpr_time_add(g_start_time, dbl_to_ts((double)x / 1000.0));
+}
+
+static gpr_atm compute_min_deadline(shard_type *shard) {
   return grpc_timer_heap_is_empty(&shard->heap)
-             ? shard->queue_deadline_cap
+             ? saturating_add(shard->queue_deadline_cap, 1)
              : grpc_timer_heap_top(&shard->heap)->deadline;
 }
 
 void grpc_timer_list_init(gpr_timespec now) {
   uint32_t i;
 
-  g_initialized = true;
-  gpr_mu_init(&g_mu);
+  g_shared_mutables.initialized = true;
+  gpr_mu_init(&g_shared_mutables.mu);
   g_clock_type = now.clock_type;
+  g_start_time = now;
+  g_shared_mutables.min_timer = timespec_to_atm_round_down(now);
+  gpr_tls_init(&g_last_seen_min_timer);
+  gpr_tls_set(&g_last_seen_min_timer, 0);
+  grpc_register_tracer("timer", &grpc_timer_trace);
+  grpc_register_tracer("timer_check", &grpc_timer_check_trace);
 
   for (i = 0; i < NUM_SHARDS; i++) {
     shard_type *shard = &g_shards[i];
     gpr_mu_init(&shard->mu);
     grpc_time_averaged_stats_init(&shard->stats, 1.0 / ADD_DEADLINE_SCALE, 0.1,
                                   0.5);
-    shard->queue_deadline_cap = now;
+    shard->queue_deadline_cap = g_shared_mutables.min_timer;
     shard->shard_queue_index = i;
     grpc_timer_heap_init(&shard->heap);
     shard->list.next = shard->list.prev = &shard->list;
@@ -110,29 +171,23 @@
 void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx) {
   int i;
   run_some_expired_timers(
-      exec_ctx, gpr_inf_future(g_clock_type), NULL,
+      exec_ctx, GPR_ATM_MAX, NULL,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Timer list shutdown"));
   for (i = 0; i < NUM_SHARDS; i++) {
     shard_type *shard = &g_shards[i];
     gpr_mu_destroy(&shard->mu);
     grpc_timer_heap_destroy(&shard->heap);
   }
-  gpr_mu_destroy(&g_mu);
-  g_initialized = false;
+  gpr_mu_destroy(&g_shared_mutables.mu);
+  gpr_tls_destroy(&g_last_seen_min_timer);
+  g_shared_mutables.initialized = false;
 }
 
 static double ts_to_dbl(gpr_timespec ts) {
   return (double)ts.tv_sec + 1e-9 * ts.tv_nsec;
 }
 
-static gpr_timespec dbl_to_ts(double d) {
-  gpr_timespec ts;
-  ts.tv_sec = (int64_t)d;
-  ts.tv_nsec = (int32_t)(1e9 * (d - (double)ts.tv_sec));
-  ts.clock_type = GPR_TIMESPAN;
-  return ts;
-}
-
+/* returns true if the first element in the list */
 static void list_join(grpc_timer *head, grpc_timer *timer) {
   timer->next = head;
   timer->prev = head->prev;
@@ -158,15 +213,13 @@
 
 static void note_deadline_change(shard_type *shard) {
   while (shard->shard_queue_index > 0 &&
-         gpr_time_cmp(
-             shard->min_deadline,
-             g_shard_queue[shard->shard_queue_index - 1]->min_deadline) < 0) {
+         shard->min_deadline <
+             g_shard_queue[shard->shard_queue_index - 1]->min_deadline) {
     swap_adjacent_shards_in_queue(shard->shard_queue_index - 1);
   }
   while (shard->shard_queue_index < NUM_SHARDS - 1 &&
-         gpr_time_cmp(
-             shard->min_deadline,
-             g_shard_queue[shard->shard_queue_index + 1]->min_deadline) > 0) {
+         shard->min_deadline >
+             g_shard_queue[shard->shard_queue_index + 1]->min_deadline) {
     swap_adjacent_shards_in_queue(shard->shard_queue_index);
   }
 }
@@ -179,9 +232,17 @@
   GPR_ASSERT(deadline.clock_type == g_clock_type);
   GPR_ASSERT(now.clock_type == g_clock_type);
   timer->closure = closure;
-  timer->deadline = deadline;
+  timer->deadline = timespec_to_atm_round_up(deadline);
 
-  if (!g_initialized) {
+  if (grpc_timer_trace) {
+    gpr_log(GPR_DEBUG, "TIMER %p: SET %" PRId64 ".%09d [%" PRIdPTR
+                       "] now %" PRId64 ".%09d [%" PRIdPTR "] call %p[%p]",
+            timer, deadline.tv_sec, deadline.tv_nsec, timer->deadline,
+            now.tv_sec, now.tv_nsec, timespec_to_atm_round_down(now), closure,
+            closure->cb);
+  }
+
+  if (!g_shared_mutables.initialized) {
     timer->pending = false;
     grpc_closure_sched(exec_ctx, timer->closure,
                        GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -201,12 +262,18 @@
 
   grpc_time_averaged_stats_add_sample(&shard->stats,
                                       ts_to_dbl(gpr_time_sub(deadline, now)));
-  if (gpr_time_cmp(deadline, shard->queue_deadline_cap) < 0) {
+  if (timer->deadline < shard->queue_deadline_cap) {
     is_first_timer = grpc_timer_heap_add(&shard->heap, timer);
   } else {
     timer->heap_index = INVALID_HEAP_INDEX;
     list_join(&shard->list, timer);
   }
+  if (grpc_timer_trace) {
+    gpr_log(GPR_DEBUG, "  .. add to shard %d with queue_deadline_cap=%" PRIdPTR
+                       " => is_first_timer=%s",
+            (int)(shard - g_shards), shard->queue_deadline_cap,
+            is_first_timer ? "true" : "false");
+  }
   gpr_mu_unlock(&shard->mu);
 
   /* Deadline may have decreased, we need to adjust the master queue.  Note
@@ -221,28 +288,41 @@
      In that case, the timer will simply have to wait for the next
      grpc_timer_check. */
   if (is_first_timer) {
-    gpr_mu_lock(&g_mu);
-    if (gpr_time_cmp(deadline, shard->min_deadline) < 0) {
-      gpr_timespec old_min_deadline = g_shard_queue[0]->min_deadline;
-      shard->min_deadline = deadline;
+    gpr_mu_lock(&g_shared_mutables.mu);
+    if (grpc_timer_trace) {
+      gpr_log(GPR_DEBUG, "  .. old shard min_deadline=%" PRIdPTR,
+              shard->min_deadline);
+    }
+    if (timer->deadline < shard->min_deadline) {
+      gpr_atm old_min_deadline = g_shard_queue[0]->min_deadline;
+      shard->min_deadline = timer->deadline;
       note_deadline_change(shard);
-      if (shard->shard_queue_index == 0 &&
-          gpr_time_cmp(deadline, old_min_deadline) < 0) {
+      if (shard->shard_queue_index == 0 && timer->deadline < old_min_deadline) {
+        gpr_atm_no_barrier_store(&g_shared_mutables.min_timer, timer->deadline);
         grpc_kick_poller();
       }
     }
-    gpr_mu_unlock(&g_mu);
+    gpr_mu_unlock(&g_shared_mutables.mu);
   }
 }
 
+void grpc_timer_consume_kick(void) {
+  /* force re-evaluation of last seeen min */
+  gpr_tls_set(&g_last_seen_min_timer, 0);
+}
+
 void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
-  if (!g_initialized) {
+  if (!g_shared_mutables.initialized) {
     /* must have already been cancelled, also the shard mutex is invalid */
     return;
   }
 
   shard_type *shard = &g_shards[GPR_HASH_POINTER(timer, NUM_SHARDS)];
   gpr_mu_lock(&shard->mu);
+  if (grpc_timer_trace) {
+    gpr_log(GPR_DEBUG, "TIMER %p: CANCEL pending=%s", timer,
+            timer->pending ? "true" : "false");
+  }
   if (timer->pending) {
     grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED);
     timer->pending = false;
@@ -260,7 +340,7 @@
    for timers that fall at or under it.  Returns true if the queue is no
    longer empty.
    REQUIRES: shard->mu locked */
-static int refill_queue(shard_type *shard, gpr_timespec now) {
+static int refill_queue(shard_type *shard, gpr_atm now) {
   /* Compute the new queue window width and bound by the limits: */
   double computed_deadline_delta =
       grpc_time_averaged_stats_update_average(&shard->stats) *
@@ -271,12 +351,22 @@
   grpc_timer *timer, *next;
 
   /* Compute the new cap and put all timers under it into the queue: */
-  shard->queue_deadline_cap = gpr_time_add(
-      gpr_time_max(now, shard->queue_deadline_cap), dbl_to_ts(deadline_delta));
+  shard->queue_deadline_cap =
+      saturating_add(GPR_MAX(now, shard->queue_deadline_cap),
+                     (gpr_atm)(deadline_delta * 1000.0));
+
+  if (grpc_timer_check_trace) {
+    gpr_log(GPR_DEBUG, "  .. shard[%d]->queue_deadline_cap --> %" PRIdPTR,
+            (int)(shard - g_shards), shard->queue_deadline_cap);
+  }
   for (timer = shard->list.next; timer != &shard->list; timer = next) {
     next = timer->next;
 
-    if (gpr_time_cmp(timer->deadline, shard->queue_deadline_cap) < 0) {
+    if (timer->deadline < shard->queue_deadline_cap) {
+      if (grpc_timer_check_trace) {
+        gpr_log(GPR_DEBUG, "  .. add timer with deadline %" PRIdPTR " to heap",
+                timer->deadline);
+      }
       list_remove(timer);
       grpc_timer_heap_add(&shard->heap, timer);
     }
@@ -287,15 +377,29 @@
 /* This pops the next non-cancelled timer with deadline <= now from the
    queue, or returns NULL if there isn't one.
    REQUIRES: shard->mu locked */
-static grpc_timer *pop_one(shard_type *shard, gpr_timespec now) {
+static grpc_timer *pop_one(shard_type *shard, gpr_atm now) {
   grpc_timer *timer;
   for (;;) {
+    if (grpc_timer_check_trace) {
+      gpr_log(GPR_DEBUG, "  .. shard[%d]: heap_empty=%s",
+              (int)(shard - g_shards),
+              grpc_timer_heap_is_empty(&shard->heap) ? "true" : "false");
+    }
     if (grpc_timer_heap_is_empty(&shard->heap)) {
-      if (gpr_time_cmp(now, shard->queue_deadline_cap) < 0) return NULL;
+      if (now < shard->queue_deadline_cap) return NULL;
       if (!refill_queue(shard, now)) return NULL;
     }
     timer = grpc_timer_heap_top(&shard->heap);
-    if (gpr_time_cmp(timer->deadline, now) > 0) return NULL;
+    if (grpc_timer_check_trace) {
+      gpr_log(GPR_DEBUG,
+              "  .. check top timer deadline=%" PRIdPTR " now=%" PRIdPTR,
+              timer->deadline, now);
+    }
+    if (timer->deadline > now) return NULL;
+    if (grpc_timer_trace) {
+      gpr_log(GPR_DEBUG, "TIMER %p: FIRE %" PRIdPTR "ms late", timer,
+              now - timer->deadline);
+    }
     timer->pending = false;
     grpc_timer_heap_pop(&shard->heap);
     return timer;
@@ -304,7 +408,7 @@
 
 /* REQUIRES: shard->mu unlocked */
 static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard,
-                         gpr_timespec now, gpr_timespec *new_min_deadline,
+                         gpr_atm now, gpr_atm *new_min_deadline,
                          grpc_error *error) {
   size_t n = 0;
   grpc_timer *timer;
@@ -318,17 +422,29 @@
   return n;
 }
 
-static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
-                                   gpr_timespec *next, grpc_error *error) {
+static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_atm now,
+                                   gpr_atm *next, grpc_error *error) {
   size_t n = 0;
 
-  /* TODO(ctiller): verify that there are any timers (atomically) here */
+  gpr_atm min_timer = gpr_atm_no_barrier_load(&g_shared_mutables.min_timer);
+  gpr_tls_set(&g_last_seen_min_timer, min_timer);
+  if (now < min_timer) {
+    if (next != NULL) *next = GPR_MIN(*next, min_timer);
+    return 0;
+  }
 
-  if (gpr_spinlock_trylock(&g_checker_mu)) {
-    gpr_mu_lock(&g_mu);
+  if (gpr_spinlock_trylock(&g_shared_mutables.checker_mu)) {
+    gpr_mu_lock(&g_shared_mutables.mu);
 
-    while (gpr_time_cmp(g_shard_queue[0]->min_deadline, now) < 0) {
-      gpr_timespec new_min_deadline;
+    if (grpc_timer_check_trace) {
+      gpr_log(GPR_DEBUG, "  .. shard[%d]->min_deadline = %" PRIdPTR,
+              (int)(g_shard_queue[0] - g_shards),
+              g_shard_queue[0]->min_deadline);
+    }
+
+    while (g_shard_queue[0]->min_deadline < now ||
+           (now != GPR_ATM_MAX && g_shard_queue[0]->min_deadline == now)) {
+      gpr_atm new_min_deadline;
 
       /* For efficiency, we pop as many available timers as we can from the
          shard.  This may violate perfect timer deadline ordering, but that
@@ -336,6 +452,14 @@
       n +=
           pop_timers(exec_ctx, g_shard_queue[0], now, &new_min_deadline, error);
 
+      if (grpc_timer_check_trace) {
+        gpr_log(GPR_DEBUG, "  .. popped --> %" PRIdPTR
+                           ", shard[%d]->min_deadline %" PRIdPTR
+                           " --> %" PRIdPTR ", now=%" PRIdPTR,
+                n, (int)(g_shard_queue[0] - g_shards),
+                g_shard_queue[0]->min_deadline, new_min_deadline, now);
+      }
+
       /* An grpc_timer_init() on the shard could intervene here, adding a new
          timer that is earlier than new_min_deadline.  However,
          grpc_timer_init() will block on the master_lock before it can call
@@ -346,23 +470,24 @@
     }
 
     if (next) {
-      *next = gpr_time_min(*next, g_shard_queue[0]->min_deadline);
+      *next = GPR_MIN(*next, g_shard_queue[0]->min_deadline);
     }
 
-    gpr_mu_unlock(&g_mu);
-    gpr_spinlock_unlock(&g_checker_mu);
+    gpr_atm_no_barrier_store(&g_shared_mutables.min_timer,
+                             g_shard_queue[0]->min_deadline);
+    gpr_mu_unlock(&g_shared_mutables.mu);
+    gpr_spinlock_unlock(&g_shared_mutables.checker_mu);
   } else if (next != NULL) {
     /* TODO(ctiller): this forces calling code to do an short poll, and
        then retry the timer check (because this time through the timer list was
        contended).
 
-       We could reduce the cost here dramatically by keeping a count of how many
-       currently active pollers got through the uncontended case above
+       We could reduce the cost here dramatically by keeping a count of how
+       many currently active pollers got through the uncontended case above
        successfully, and waking up other pollers IFF that count drops to zero.
 
        Once that count is in place, this entire else branch could disappear. */
-    *next = gpr_time_min(
-        *next, gpr_time_add(now, gpr_time_from_millis(1, GPR_TIMESPAN)));
+    *next = GPR_MIN(*next, now + 1);
   }
 
   GRPC_ERROR_UNREF(error);
@@ -372,12 +497,71 @@
 
 bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now,
                       gpr_timespec *next) {
+  // prelude
   GPR_ASSERT(now.clock_type == g_clock_type);
-  return run_some_expired_timers(
-      exec_ctx, now, next,
+  gpr_atm now_atm = timespec_to_atm_round_down(now);
+
+  /* fetch from a thread-local first: this avoids contention on a globally
+     mutable cacheline in the common case */
+  gpr_atm min_timer = gpr_tls_get(&g_last_seen_min_timer);
+  if (now_atm < min_timer) {
+    if (next != NULL) {
+      *next =
+          atm_to_timespec(GPR_MIN(timespec_to_atm_round_up(*next), min_timer));
+    }
+    if (grpc_timer_check_trace) {
+      gpr_log(GPR_DEBUG,
+              "TIMER CHECK SKIP: now_atm=%" PRIdPTR " min_timer=%" PRIdPTR,
+              now_atm, min_timer);
+    }
+    return 0;
+  }
+
+  grpc_error *shutdown_error =
       gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0
           ? GRPC_ERROR_NONE
-          : GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutting down timer system"));
+          : GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutting down timer system");
+
+  // tracing
+  if (grpc_timer_check_trace) {
+    char *next_str;
+    if (next == NULL) {
+      next_str = gpr_strdup("NULL");
+    } else {
+      gpr_asprintf(&next_str, "%" PRId64 ".%09d [%" PRIdPTR "]", next->tv_sec,
+                   next->tv_nsec, timespec_to_atm_round_down(*next));
+    }
+    gpr_log(GPR_DEBUG, "TIMER CHECK BEGIN: now=%" PRId64 ".%09d [%" PRIdPTR
+                       "] next=%s tls_min=%" PRIdPTR " glob_min=%" PRIdPTR,
+            now.tv_sec, now.tv_nsec, now_atm, next_str,
+            gpr_tls_get(&g_last_seen_min_timer),
+            gpr_atm_no_barrier_load(&g_shared_mutables.min_timer));
+    gpr_free(next_str);
+  }
+  // actual code
+  bool r;
+  gpr_atm next_atm;
+  if (next == NULL) {
+    r = run_some_expired_timers(exec_ctx, now_atm, NULL, shutdown_error);
+  } else {
+    next_atm = timespec_to_atm_round_down(*next);
+    r = run_some_expired_timers(exec_ctx, now_atm, &next_atm, shutdown_error);
+    *next = atm_to_timespec(next_atm);
+  }
+  // tracing
+  if (grpc_timer_check_trace) {
+    char *next_str;
+    if (next == NULL) {
+      next_str = gpr_strdup("NULL");
+    } else {
+      gpr_asprintf(&next_str, "%" PRId64 ".%09d [%" PRIdPTR "]", next->tv_sec,
+                   next->tv_nsec, next_atm);
+    }
+    gpr_log(GPR_DEBUG, "TIMER CHECK END: %d timers triggered; next=%s", r,
+            next_str);
+    gpr_free(next_str);
+  }
+  return r > 0;
 }
 
 #endif /* GRPC_TIMER_USE_GENERIC */
diff --git a/src/core/lib/iomgr/timer_generic.h b/src/core/lib/iomgr/timer_generic.h
index 1608dce..c79a431 100644
--- a/src/core/lib/iomgr/timer_generic.h
+++ b/src/core/lib/iomgr/timer_generic.h
@@ -38,7 +38,7 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 
 struct grpc_timer {
-  gpr_timespec deadline;
+  gpr_atm deadline;
   uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */
   bool pending;
   struct grpc_timer *next;
diff --git a/src/core/lib/iomgr/timer_heap.c b/src/core/lib/iomgr/timer_heap.c
index f736d33..03ccfe0 100644
--- a/src/core/lib/iomgr/timer_heap.c
+++ b/src/core/lib/iomgr/timer_heap.c
@@ -50,7 +50,7 @@
 static void adjust_upwards(grpc_timer **first, uint32_t i, grpc_timer *t) {
   while (i > 0) {
     uint32_t parent = (uint32_t)(((int)i - 1) / 2);
-    if (gpr_time_cmp(first[parent]->deadline, t->deadline) <= 0) break;
+    if (first[parent]->deadline <= t->deadline) break;
     first[i] = first[parent];
     first[i]->heap_index = i;
     i = parent;
@@ -68,12 +68,12 @@
     uint32_t left_child = 1u + 2u * i;
     if (left_child >= length) break;
     uint32_t right_child = left_child + 1;
-    uint32_t next_i = right_child < length &&
-                              gpr_time_cmp(first[left_child]->deadline,
-                                           first[right_child]->deadline) > 0
-                          ? right_child
-                          : left_child;
-    if (gpr_time_cmp(t->deadline, first[next_i]->deadline) <= 0) break;
+    uint32_t next_i =
+        right_child < length &&
+                first[left_child]->deadline > first[right_child]->deadline
+            ? right_child
+            : left_child;
+    if (t->deadline <= first[next_i]->deadline) break;
     first[i] = first[next_i];
     first[i]->heap_index = i;
     i = next_i;
@@ -97,7 +97,7 @@
 static void note_changed_priority(grpc_timer_heap *heap, grpc_timer *timer) {
   uint32_t i = timer->heap_index;
   uint32_t parent = (uint32_t)(((int)i - 1) / 2);
-  if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) > 0) {
+  if (heap->timers[parent]->deadline > timer->deadline) {
     adjust_upwards(heap->timers, i, timer);
   } else {
     adjust_downwards(heap->timers, i, heap->timer_count, timer);
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index 8f321b9..f526653 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -64,7 +64,7 @@
      pollset_set so that work can progress when this call wants work to progress
   */
   grpc_polling_entity *pollent;
-  grpc_transport_stream_op op;
+  grpc_transport_stream_op_batch op;
   uint8_t security_context_set;
   grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
   grpc_auth_metadata_context auth_md_context;
@@ -108,7 +108,7 @@
                                     const char *error_details) {
   grpc_call_element *elem = (grpc_call_element *)user_data;
   call_data *calld = elem->call_data;
-  grpc_transport_stream_op *op = &calld->op;
+  grpc_transport_stream_op_batch *op = &calld->op;
   grpc_metadata_batch *mdb;
   size_t i;
   reset_auth_metadata_context(&calld->auth_md_context);
@@ -122,8 +122,8 @@
         GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAUTHENTICATED);
   } else {
     GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT);
-    GPR_ASSERT(op->send_initial_metadata != NULL);
-    mdb = op->send_initial_metadata;
+    GPR_ASSERT(op->send_initial_metadata);
+    mdb = op->payload->send_initial_metadata.send_initial_metadata;
     for (i = 0; i < num_md; i++) {
       add_error(&error,
                 grpc_metadata_batch_add_tail(
@@ -136,7 +136,7 @@
   if (error == GRPC_ERROR_NONE) {
     grpc_call_next_op(exec_ctx, elem, op);
   } else {
-    grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+    grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
   }
 }
 
@@ -172,11 +172,13 @@
 
 static void send_security_metadata(grpc_exec_ctx *exec_ctx,
                                    grpc_call_element *elem,
-                                   grpc_transport_stream_op *op) {
+                                   grpc_transport_stream_op_batch *op) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   grpc_client_security_context *ctx =
-      (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value;
+      (grpc_client_security_context *)op->payload
+          ->context[GRPC_CONTEXT_SECURITY]
+          .value;
   grpc_call_credentials *channel_call_creds =
       chand->security_connector->request_metadata_creds;
   int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL);
@@ -191,7 +193,7 @@
     calld->creds = grpc_composite_call_credentials_create(channel_call_creds,
                                                           ctx->creds, NULL);
     if (calld->creds == NULL) {
-      grpc_transport_stream_op_finish_with_failure(
+      grpc_transport_stream_op_batch_finish_with_failure(
           exec_ctx, op,
           grpc_error_set_int(
               GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -242,7 +244,7 @@
    that is being sent or received. */
 static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
                                     grpc_call_element *elem,
-                                    grpc_transport_stream_op *op) {
+                                    grpc_transport_stream_op_batch *op) {
   GPR_TIMER_BEGIN("auth_start_transport_op", 0);
 
   /* grab pointers to our data from the call element */
@@ -251,23 +253,25 @@
   grpc_linked_mdelem *l;
   grpc_client_security_context *sec_ctx = NULL;
 
-  if (calld->security_context_set == 0 && op->cancel_error == GRPC_ERROR_NONE) {
+  if (calld->security_context_set == 0 && !op->cancel_stream) {
     calld->security_context_set = 1;
-    GPR_ASSERT(op->context);
-    if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) {
-      op->context[GRPC_CONTEXT_SECURITY].value =
+    GPR_ASSERT(op->payload->context != NULL);
+    if (op->payload->context[GRPC_CONTEXT_SECURITY].value == NULL) {
+      op->payload->context[GRPC_CONTEXT_SECURITY].value =
           grpc_client_security_context_create();
-      op->context[GRPC_CONTEXT_SECURITY].destroy =
+      op->payload->context[GRPC_CONTEXT_SECURITY].destroy =
           grpc_client_security_context_destroy;
     }
-    sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value;
+    sec_ctx = op->payload->context[GRPC_CONTEXT_SECURITY].value;
     GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter");
     sec_ctx->auth_context =
         GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter");
   }
 
-  if (op->send_initial_metadata != NULL) {
-    for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) {
+  if (op->send_initial_metadata) {
+    for (l = op->payload->send_initial_metadata.send_initial_metadata->list
+                 .head;
+         l != NULL; l = l->next) {
       grpc_mdelem md = l->md;
       /* Pointer comparison is OK for md_elems created from the same context.
        */
diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c
index 2f39327..509b4b5 100644
--- a/src/core/lib/security/transport/security_handshaker.c
+++ b/src/core/lib/security/transport/security_handshaker.c
@@ -287,12 +287,11 @@
   if (num_left_overs > 0) {
     /* Put the leftovers in our buffer (ownership transfered). */
     if (has_left_overs_in_current_slice) {
-      grpc_slice_buffer_add(
-          &h->left_overs,
-          grpc_slice_split_tail(&h->args->read_buffer->slices[i],
-                                consumed_slice_size));
+      grpc_slice tail = grpc_slice_split_tail(&h->args->read_buffer->slices[i],
+                                              consumed_slice_size);
+      grpc_slice_buffer_add(&h->left_overs, tail);
       /* split_tail above increments refcount. */
-      grpc_slice_unref_internal(exec_ctx, h->args->read_buffer->slices[i]);
+      grpc_slice_unref_internal(exec_ctx, tail);
     }
     grpc_slice_buffer_addn(
         &h->left_overs, &h->args->read_buffer->slices[i + 1],
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index 3cf0632..1aca76f 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -49,7 +49,7 @@
      up-call on transport_op, and remember to call our on_done_recv member after
      handling it. */
   grpc_closure auth_on_recv;
-  grpc_transport_stream_op *transport_op;
+  grpc_transport_stream_op_batch *transport_op;
   grpc_metadata_array md;
   const grpc_metadata *consumed_md;
   size_t num_consumed_md;
@@ -138,12 +138,11 @@
     error_details = error_details != NULL
                         ? error_details
                         : "Authentication metadata processing failed.";
-    calld->transport_op->send_initial_metadata = NULL;
-    if (calld->transport_op->send_message != NULL) {
-      grpc_byte_stream_destroy(&exec_ctx, calld->transport_op->send_message);
-      calld->transport_op->send_message = NULL;
+    if (calld->transport_op->send_message) {
+      grpc_byte_stream_destroy(
+          &exec_ctx, calld->transport_op->payload->send_message.send_message);
+      calld->transport_op->payload->send_message.send_message = NULL;
     }
-    calld->transport_op->send_trailing_metadata = NULL;
     grpc_closure_sched(
         &exec_ctx, calld->on_done_recv,
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_details),
@@ -171,14 +170,17 @@
 }
 
 static void set_recv_ops_md_callbacks(grpc_call_element *elem,
-                                      grpc_transport_stream_op *op) {
+                                      grpc_transport_stream_op_batch *op) {
   call_data *calld = elem->call_data;
 
-  if (op->recv_initial_metadata != NULL) {
+  if (op->recv_initial_metadata) {
     /* substitute our callback for the higher callback */
-    calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = &calld->auth_on_recv;
+    calld->recv_initial_metadata =
+        op->payload->recv_initial_metadata.recv_initial_metadata;
+    calld->on_done_recv =
+        op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+    op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+        &calld->auth_on_recv;
     calld->transport_op = op;
   }
 }
@@ -190,7 +192,7 @@
    that is being sent or received. */
 static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
                                     grpc_call_element *elem,
-                                    grpc_transport_stream_op *op) {
+                                    grpc_transport_stream_op_batch *op) {
   set_recv_ops_md_callbacks(elem, op);
   grpc_call_next_op(exec_ctx, elem, op);
 }
diff --git a/src/core/lib/slice/slice_buffer.c b/src/core/lib/slice/slice_buffer.c
index 9176dc8..c96b9c3 100644
--- a/src/core/lib/slice/slice_buffer.c
+++ b/src/core/lib/slice/slice_buffer.c
@@ -46,27 +46,29 @@
 #define GROW(x) (3 * (x) / 2)
 
 static void maybe_embiggen(grpc_slice_buffer *sb) {
-  if (sb->base_slices != sb->slices) {
-    memmove(sb->base_slices, sb->slices, sb->count * sizeof(grpc_slice));
-    sb->slices = sb->base_slices;
-  }
-
   /* How far away from sb->base_slices is sb->slices pointer */
   size_t slice_offset = (size_t)(sb->slices - sb->base_slices);
   size_t slice_count = sb->count + slice_offset;
 
   if (slice_count == sb->capacity) {
-    sb->capacity = GROW(sb->capacity);
-    GPR_ASSERT(sb->capacity > slice_count);
-    if (sb->base_slices == sb->inlined) {
-      sb->base_slices = gpr_malloc(sb->capacity * sizeof(grpc_slice));
-      memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice));
+    if (sb->base_slices != sb->slices) {
+      /* Make room by moving elements if there's still space unused */
+      memmove(sb->base_slices, sb->slices, sb->count * sizeof(grpc_slice));
+      sb->slices = sb->base_slices;
     } else {
-      sb->base_slices =
-          gpr_realloc(sb->base_slices, sb->capacity * sizeof(grpc_slice));
-    }
+      /* Allocate more memory if no more space is available */
+      sb->capacity = GROW(sb->capacity);
+      GPR_ASSERT(sb->capacity > slice_count);
+      if (sb->base_slices == sb->inlined) {
+        sb->base_slices = gpr_malloc(sb->capacity * sizeof(grpc_slice));
+        memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice));
+      } else {
+        sb->base_slices =
+            gpr_realloc(sb->base_slices, sb->capacity * sizeof(grpc_slice));
+      }
 
-    sb->slices = sb->base_slices + slice_offset;
+      sb->slices = sb->base_slices + slice_offset;
+    }
   }
 }
 
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index a9317a4..97d50a9 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -117,37 +117,56 @@
 
 typedef struct batch_control {
   grpc_call *call;
-  grpc_cq_completion cq_completion;
+  /* Share memory for cq_completion and notify_tag as they are never needed
+     simultaneously. Each byte used in this data structure count as six bytes
+     per call, so any savings we can make are worthwhile,
+
+     We use notify_tag to determine whether or not to send notification to the
+     completion queue. Once we've made that determination, we can reuse the
+     memory for cq_completion. */
+  union {
+    grpc_cq_completion cq_completion;
+    struct {
+      /* Any given op indicates completion by either (a) calling a closure or
+         (b) sending a notification on the call's completion queue.  If
+         \a is_closure is true, \a tag indicates a closure to be invoked;
+         otherwise, \a tag indicates the tag to be used in the notification to
+         be sent to the completion queue. */
+      void *tag;
+      bool is_closure;
+    } notify_tag;
+  } completion_data;
   grpc_closure finish_batch;
-  void *notify_tag;
   gpr_refcount steps_to_complete;
 
   grpc_error *errors[MAX_ERRORS_PER_BATCH];
   gpr_atm num_errors;
 
-  uint8_t send_initial_metadata;
-  uint8_t send_message;
-  uint8_t send_final_op;
-  uint8_t recv_initial_metadata;
-  uint8_t recv_message;
-  uint8_t recv_final_op;
-  uint8_t is_notify_tag_closure;
-
-  /* TODO(ctiller): now that this is inlined, figure out how much of the above
-                    state can be eliminated */
-  grpc_transport_stream_op op;
+  grpc_transport_stream_op_batch op;
 } batch_control;
 
+typedef struct {
+  gpr_mu child_list_mu;
+  grpc_call *first_child;
+} parent_call;
+
+typedef struct {
+  grpc_call *parent;
+  /** siblings: children of the same parent form a list, and this list is
+     protected under
+      parent->mu */
+  grpc_call *sibling_next;
+  grpc_call *sibling_prev;
+} child_call;
+
 struct grpc_call {
   gpr_arena *arena;
   grpc_completion_queue *cq;
   grpc_polling_entity pollent;
   grpc_channel *channel;
-  grpc_call *parent;
-  grpc_call *first_child;
   gpr_timespec start_time;
-  /* protects first_child, and child next/prev links */
-  gpr_mu child_list_mu;
+  /* parent_call* */ gpr_atm parent_call_atm;
+  child_call *child_call;
 
   /* client or server call */
   bool is_client;
@@ -168,7 +187,8 @@
   /* have we received initial metadata */
   bool has_initial_md_been_received;
 
-  batch_control active_batches[MAX_CONCURRENT_BATCHES];
+  batch_control *active_batches[MAX_CONCURRENT_BATCHES];
+  grpc_transport_stream_op_batch_payload stream_op_payload;
 
   /* first idx: is_receiving, second idx: is_trailing */
   grpc_metadata_batch metadata_batch[2][2];
@@ -198,12 +218,6 @@
   int send_extra_metadata_count;
   gpr_timespec send_deadline;
 
-  /** siblings: children of the same parent form a list, and this list is
-     protected under
-      parent->mu */
-  grpc_call *sibling_next;
-  grpc_call *sibling_prev;
-
   grpc_slice_buffer_stream sending_stream;
 
   grpc_byte_stream *receiving_stream;
@@ -239,7 +253,7 @@
   CALL_FROM_CALL_STACK(grpc_call_stack_from_top_element(top_elem))
 
 static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
-                       grpc_transport_stream_op *op);
+                       grpc_transport_stream_op_batch *op);
 static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
                                status_source source, grpc_status_code status,
                                const char *description);
@@ -268,6 +282,23 @@
   *composite = grpc_error_add_child(*composite, new);
 }
 
+static parent_call *get_or_create_parent_call(grpc_call *call) {
+  parent_call *p = (parent_call *)gpr_atm_acq_load(&call->parent_call_atm);
+  if (p == NULL) {
+    p = gpr_arena_alloc(call->arena, sizeof(*p));
+    gpr_mu_init(&p->child_list_mu);
+    if (!gpr_atm_rel_cas(&call->parent_call_atm, (gpr_atm)NULL, (gpr_atm)p)) {
+      gpr_mu_destroy(&p->child_list_mu);
+      p = (parent_call *)gpr_atm_acq_load(&call->parent_call_atm);
+    }
+  }
+  return p;
+}
+
+static parent_call *get_parent_call(grpc_call *call) {
+  return (parent_call *)gpr_atm_acq_load(&call->parent_call_atm);
+}
+
 grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
                              const grpc_call_create_args *args,
                              grpc_call **out_call) {
@@ -283,14 +314,13 @@
                          sizeof(grpc_call) + channel_stack->call_stack_size);
   call->arena = arena;
   *out_call = call;
-  gpr_mu_init(&call->child_list_mu);
   call->channel = args->channel;
   call->cq = args->cq;
-  call->parent = args->parent_call;
   call->start_time = gpr_now(GPR_CLOCK_MONOTONIC);
   /* Always support no compression */
   GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
   call->is_client = args->server_transport_data == NULL;
+  call->stream_op_payload.context = call->context;
   grpc_slice path = grpc_empty_slice();
   if (call->is_client) {
     GPR_ASSERT(args->add_initial_metadata_count <
@@ -317,11 +347,17 @@
       gpr_convert_clock_type(args->send_deadline, GPR_CLOCK_MONOTONIC);
 
   if (args->parent_call != NULL) {
+    child_call *cc = call->child_call =
+        gpr_arena_alloc(arena, sizeof(child_call));
+    call->child_call->parent = args->parent_call;
+
     GRPC_CALL_INTERNAL_REF(args->parent_call, "child");
     GPR_ASSERT(call->is_client);
     GPR_ASSERT(!args->parent_call->is_client);
 
-    gpr_mu_lock(&args->parent_call->child_list_mu);
+    parent_call *pc = get_or_create_parent_call(args->parent_call);
+
+    gpr_mu_lock(&pc->child_list_mu);
 
     if (args->propagation_mask & GRPC_PROPAGATE_DEADLINE) {
       send_deadline = gpr_time_min(
@@ -355,17 +391,17 @@
       }
     }
 
-    if (args->parent_call->first_child == NULL) {
-      args->parent_call->first_child = call;
-      call->sibling_next = call->sibling_prev = call;
+    if (pc->first_child == NULL) {
+      pc->first_child = call;
+      cc->sibling_next = cc->sibling_prev = call;
     } else {
-      call->sibling_next = args->parent_call->first_child;
-      call->sibling_prev = args->parent_call->first_child->sibling_prev;
-      call->sibling_next->sibling_prev = call->sibling_prev->sibling_next =
-          call;
+      cc->sibling_next = pc->first_child;
+      cc->sibling_prev = pc->first_child->child_call->sibling_prev;
+      cc->sibling_next->child_call->sibling_prev =
+          cc->sibling_prev->child_call->sibling_next = call;
     }
 
-    gpr_mu_unlock(&args->parent_call->child_list_mu);
+    gpr_mu_unlock(&pc->child_list_mu);
   }
 
   call->send_deadline = send_deadline;
@@ -460,7 +496,10 @@
   if (c->receiving_stream != NULL) {
     grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
   }
-  gpr_mu_destroy(&c->child_list_mu);
+  parent_call *pc = get_parent_call(c);
+  if (pc != NULL) {
+    gpr_mu_destroy(&pc->child_list_mu);
+  }
   for (ii = 0; ii < c->send_extra_metadata_count; ii++) {
     GRPC_MDELEM_UNREF(exec_ctx, c->send_extra_metadata[ii].md);
   }
@@ -490,31 +529,31 @@
 }
 
 void grpc_call_destroy(grpc_call *c) {
-  int cancel;
-  grpc_call *parent = c->parent;
+  child_call *cc = c->child_call;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   GPR_TIMER_BEGIN("grpc_call_destroy", 0);
   GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
 
-  if (parent) {
-    gpr_mu_lock(&parent->child_list_mu);
-    if (c == parent->first_child) {
-      parent->first_child = c->sibling_next;
-      if (c == parent->first_child) {
-        parent->first_child = NULL;
+  if (cc) {
+    parent_call *pc = get_parent_call(cc->parent);
+    gpr_mu_lock(&pc->child_list_mu);
+    if (c == pc->first_child) {
+      pc->first_child = cc->sibling_next;
+      if (c == pc->first_child) {
+        pc->first_child = NULL;
       }
     }
-    c->sibling_prev->sibling_next = c->sibling_next;
-    c->sibling_next->sibling_prev = c->sibling_prev;
-    gpr_mu_unlock(&parent->child_list_mu);
-    GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
+    cc->sibling_prev->child_call->sibling_next = cc->sibling_next;
+    cc->sibling_next->child_call->sibling_prev = cc->sibling_prev;
+    gpr_mu_unlock(&pc->child_list_mu);
+    GRPC_CALL_INTERNAL_UNREF(&exec_ctx, cc->parent, "child");
   }
 
   GPR_ASSERT(!c->destroy_called);
   c->destroy_called = 1;
-  cancel = gpr_atm_acq_load(&c->any_ops_sent_atm) &&
-           !gpr_atm_acq_load(&c->received_final_op_atm);
+  bool cancel = gpr_atm_acq_load(&c->any_ops_sent_atm) != 0 &&
+                gpr_atm_acq_load(&c->received_final_op_atm) == 0;
   if (cancel) {
     cancel_with_error(&exec_ctx, c, STATUS_FROM_API_OVERRIDE,
                       GRPC_ERROR_CANCELLED);
@@ -535,13 +574,12 @@
 }
 
 static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
-                       grpc_transport_stream_op *op) {
+                       grpc_transport_stream_op_batch *op) {
   grpc_call_element *elem;
 
   GPR_TIMER_BEGIN("execute_op", 0);
   elem = CALL_ELEM_FROM_CALL(call, 0);
-  op->context = call->context;
-  elem->filter->start_transport_stream_op(exec_ctx, elem, op);
+  elem->filter->start_transport_stream_op_batch(exec_ctx, elem, op);
   GPR_TIMER_END("execute_op", 0);
 }
 
@@ -594,9 +632,10 @@
                               status_source source, grpc_error *error) {
   GRPC_CALL_INTERNAL_REF(c, "termination");
   set_status_from_error(exec_ctx, c, source, GRPC_ERROR_REF(error));
-  grpc_transport_stream_op *op = grpc_make_transport_stream_op(
+  grpc_transport_stream_op_batch *op = grpc_make_transport_stream_op(
       grpc_closure_create(done_termination, c, grpc_schedule_on_exec_ctx));
-  op->cancel_error = error;
+  op->cancel_stream = true;
+  op->payload->cancel_stream.cancel_error = error;
   execute_op(exec_ctx, c, op);
 }
 
@@ -1025,16 +1064,17 @@
                                              const grpc_op *ops,
                                              size_t num_ops) {
   int slot = batch_slot_for_op(ops[0].op);
-  for (size_t i = 1; i < num_ops; i++) {
-    int op_slot = batch_slot_for_op(ops[i].op);
-    slot = GPR_MIN(slot, op_slot);
+  batch_control **pslot = &call->active_batches[slot];
+  if (*pslot == NULL) {
+    *pslot = gpr_arena_alloc(call->arena, sizeof(batch_control));
   }
-  batch_control *bctl = &call->active_batches[slot];
+  batch_control *bctl = *pslot;
   if (bctl->call != NULL) {
     return NULL;
   }
   memset(bctl, 0, sizeof(*bctl));
   bctl->call = call;
+  bctl->op.payload = &call->stream_op_payload;
   return bctl;
 }
 
@@ -1069,46 +1109,49 @@
 
 static void post_batch_completion(grpc_exec_ctx *exec_ctx,
                                   batch_control *bctl) {
-  grpc_call *child_call;
   grpc_call *next_child_call;
   grpc_call *call = bctl->call;
   grpc_error *error = consolidate_batch_errors(bctl);
 
-  if (bctl->send_initial_metadata) {
+  if (bctl->op.send_initial_metadata) {
     grpc_metadata_batch_destroy(
         exec_ctx,
         &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]);
   }
-  if (bctl->send_message) {
+  if (bctl->op.send_message) {
     call->sending_message = false;
   }
-  if (bctl->send_final_op) {
+  if (bctl->op.send_trailing_metadata) {
     grpc_metadata_batch_destroy(
         exec_ctx,
         &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
   }
-  if (bctl->recv_final_op) {
+  if (bctl->op.recv_trailing_metadata) {
     grpc_metadata_batch *md =
         &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
     recv_trailing_filter(exec_ctx, call, md);
 
     /* propagate cancellation to any interested children */
     gpr_atm_rel_store(&call->received_final_op_atm, 1);
-    gpr_mu_lock(&call->child_list_mu);
-    child_call = call->first_child;
-    if (child_call != NULL) {
-      do {
-        next_child_call = child_call->sibling_next;
-        if (child_call->cancellation_is_inherited) {
-          GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
-          cancel_with_error(exec_ctx, child_call, STATUS_FROM_API_OVERRIDE,
-                            GRPC_ERROR_CANCELLED);
-          GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
-        }
-        child_call = next_child_call;
-      } while (child_call != call->first_child);
+    parent_call *pc = get_parent_call(call);
+    if (pc != NULL) {
+      grpc_call *child;
+      gpr_mu_lock(&pc->child_list_mu);
+      child = pc->first_child;
+      if (child != NULL) {
+        do {
+          next_child_call = child->child_call->sibling_next;
+          if (child->cancellation_is_inherited) {
+            GRPC_CALL_INTERNAL_REF(child, "propagate_cancel");
+            cancel_with_error(exec_ctx, child, STATUS_FROM_API_OVERRIDE,
+                              GRPC_ERROR_CANCELLED);
+            GRPC_CALL_INTERNAL_UNREF(exec_ctx, child, "propagate_cancel");
+          }
+          child = next_child_call;
+        } while (child != pc->first_child);
+      }
+      gpr_mu_unlock(&pc->child_list_mu);
     }
-    gpr_mu_unlock(&call->child_list_mu);
 
     if (call->is_client) {
       get_final_status(call, set_status_value_directly,
@@ -1123,15 +1166,16 @@
     error = GRPC_ERROR_NONE;
   }
 
-  if (bctl->is_notify_tag_closure) {
+  if (bctl->completion_data.notify_tag.is_closure) {
     /* unrefs bctl->error */
     bctl->call = NULL;
-    grpc_closure_run(exec_ctx, bctl->notify_tag, error);
+    grpc_closure_run(exec_ctx, bctl->completion_data.notify_tag.tag, error);
     GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
   } else {
     /* unrefs bctl->error */
-    grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, error,
-                   finish_batch_completion, bctl, &bctl->cq_completion);
+    grpc_cq_end_op(
+        exec_ctx, bctl->call->cq, bctl->completion_data.notify_tag.tag, error,
+        finish_batch_completion, bctl, &bctl->completion_data.cq_completion);
   }
 }
 
@@ -1374,11 +1418,13 @@
   if (bctl == NULL) {
     return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
   }
-  bctl->notify_tag = notify_tag;
-  bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0);
+  bctl->completion_data.notify_tag.tag = notify_tag;
+  bctl->completion_data.notify_tag.is_closure =
+      (uint8_t)(is_notify_tag_closure != 0);
 
-  grpc_transport_stream_op *stream_op = &bctl->op;
-  memset(stream_op, 0, sizeof(*stream_op));
+  grpc_transport_stream_op_batch *stream_op = &bctl->op;
+  grpc_transport_stream_op_batch_payload *stream_op_payload =
+      &call->stream_op_payload;
   stream_op->covered_by_poller = true;
 
   /* rewrite batch ops into a transport op */
@@ -1432,8 +1478,8 @@
           error = GRPC_CALL_ERROR_INVALID_METADATA;
           goto done_with_error;
         }
-        bctl->send_initial_metadata = 1;
-        call->sent_initial_metadata = 1;
+        stream_op->send_initial_metadata = true;
+        call->sent_initial_metadata = true;
         if (!prepare_application_metadata(
                 exec_ctx, call, (int)op->data.send_initial_metadata.count,
                 op->data.send_initial_metadata.metadata, 0, call->is_client,
@@ -1443,9 +1489,10 @@
         }
         /* TODO(ctiller): just make these the same variable? */
         call->metadata_batch[0][0].deadline = call->send_deadline;
-        stream_op->send_initial_metadata =
+        stream_op_payload->send_initial_metadata.send_initial_metadata =
             &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */];
-        stream_op->send_initial_metadata_flags = op->flags;
+        stream_op_payload->send_initial_metadata.send_initial_metadata_flags =
+            op->flags;
         break;
       case GRPC_OP_SEND_MESSAGE:
         if (!are_write_flags_valid(op->flags)) {
@@ -1460,8 +1507,8 @@
           error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
           goto done_with_error;
         }
-        bctl->send_message = 1;
-        call->sending_message = 1;
+        stream_op->send_message = true;
+        call->sending_message = true;
         grpc_slice_buffer_stream_init(
             &call->sending_stream,
             &op->data.send_message.send_message->data.raw.slice_buffer,
@@ -1473,7 +1520,8 @@
             GRPC_COMPRESS_NONE) {
           call->sending_stream.base.flags |= GRPC_WRITE_INTERNAL_COMPRESS;
         }
-        stream_op->send_message = &call->sending_stream.base;
+        stream_op_payload->send_message.send_message =
+            &call->sending_stream.base;
         break;
       case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
         /* Flag validation: currently allow no flags */
@@ -1489,9 +1537,9 @@
           error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
           goto done_with_error;
         }
-        bctl->send_final_op = 1;
-        call->sent_final_op = 1;
-        stream_op->send_trailing_metadata =
+        stream_op->send_trailing_metadata = true;
+        call->sent_final_op = true;
+        stream_op_payload->send_trailing_metadata.send_trailing_metadata =
             &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
         break;
       case GRPC_OP_SEND_STATUS_FROM_SERVER:
@@ -1513,8 +1561,8 @@
           error = GRPC_CALL_ERROR_INVALID_METADATA;
           goto done_with_error;
         }
-        bctl->send_final_op = 1;
-        call->sent_final_op = 1;
+        stream_op->send_trailing_metadata = true;
+        call->sent_final_op = true;
         GPR_ASSERT(call->send_extra_metadata_count == 0);
         call->send_extra_metadata_count = 1;
         call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem(
@@ -1553,7 +1601,7 @@
           error = GRPC_CALL_ERROR_INVALID_METADATA;
           goto done_with_error;
         }
-        stream_op->send_trailing_metadata =
+        stream_op_payload->send_trailing_metadata.send_trailing_metadata =
             &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
         break;
       case GRPC_OP_RECV_INITIAL_METADATA:
@@ -1570,16 +1618,16 @@
            from server.c. In that case, it's coming from accept_stream, and in
            that case we're not necessarily covered by a poller. */
         stream_op->covered_by_poller = call->is_client;
-        call->received_initial_metadata = 1;
+        call->received_initial_metadata = true;
         call->buffered_metadata[0] =
             op->data.recv_initial_metadata.recv_initial_metadata;
         grpc_closure_init(&call->receiving_initial_metadata_ready,
                           receiving_initial_metadata_ready, bctl,
                           grpc_schedule_on_exec_ctx);
-        bctl->recv_initial_metadata = 1;
-        stream_op->recv_initial_metadata =
+        stream_op->recv_initial_metadata = true;
+        stream_op_payload->recv_initial_metadata.recv_initial_metadata =
             &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
-        stream_op->recv_initial_metadata_ready =
+        stream_op_payload->recv_initial_metadata.recv_initial_metadata_ready =
             &call->receiving_initial_metadata_ready;
         num_completion_callbacks_needed++;
         break;
@@ -1593,13 +1641,14 @@
           error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
           goto done_with_error;
         }
-        call->receiving_message = 1;
-        bctl->recv_message = 1;
+        call->receiving_message = true;
+        stream_op->recv_message = true;
         call->receiving_buffer = op->data.recv_message.recv_message;
-        stream_op->recv_message = &call->receiving_stream;
+        stream_op_payload->recv_message.recv_message = &call->receiving_stream;
         grpc_closure_init(&call->receiving_stream_ready, receiving_stream_ready,
                           bctl, grpc_schedule_on_exec_ctx);
-        stream_op->recv_message_ready = &call->receiving_stream_ready;
+        stream_op_payload->recv_message.recv_message_ready =
+            &call->receiving_stream_ready;
         num_completion_callbacks_needed++;
         break;
       case GRPC_OP_RECV_STATUS_ON_CLIENT:
@@ -1616,16 +1665,17 @@
           error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
           goto done_with_error;
         }
-        call->requested_final_op = 1;
+        call->requested_final_op = true;
         call->buffered_metadata[1] =
             op->data.recv_status_on_client.trailing_metadata;
         call->final_op.client.status = op->data.recv_status_on_client.status;
         call->final_op.client.status_details =
             op->data.recv_status_on_client.status_details;
-        bctl->recv_final_op = 1;
-        stream_op->recv_trailing_metadata =
+        stream_op->recv_trailing_metadata = true;
+        stream_op->collect_stats = true;
+        stream_op_payload->recv_trailing_metadata.recv_trailing_metadata =
             &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
-        stream_op->collect_stats =
+        stream_op_payload->collect_stats.collect_stats =
             &call->final_info.stats.transport_stream_stats;
         break;
       case GRPC_OP_RECV_CLOSE_ON_SERVER:
@@ -1642,13 +1692,14 @@
           error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
           goto done_with_error;
         }
-        call->requested_final_op = 1;
+        call->requested_final_op = true;
         call->final_op.server.cancelled =
             op->data.recv_close_on_server.cancelled;
-        bctl->recv_final_op = 1;
-        stream_op->recv_trailing_metadata =
+        stream_op->recv_trailing_metadata = true;
+        stream_op->collect_stats = true;
+        stream_op_payload->recv_trailing_metadata.recv_trailing_metadata =
             &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
-        stream_op->collect_stats =
+        stream_op_payload->collect_stats.collect_stats =
             &call->final_info.stats.transport_stream_stats;
         break;
     }
@@ -1660,7 +1711,6 @@
   }
   gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed);
 
-  stream_op->context = call->context;
   grpc_closure_init(&bctl->finish_batch, finish_batch, bctl,
                     grpc_schedule_on_exec_ctx);
   stream_op->on_complete = &bctl->finish_batch;
@@ -1674,26 +1724,26 @@
 
 done_with_error:
   /* reverse any mutations that occured */
-  if (bctl->send_initial_metadata) {
-    call->sent_initial_metadata = 0;
+  if (stream_op->send_initial_metadata) {
+    call->sent_initial_metadata = false;
     grpc_metadata_batch_clear(exec_ctx, &call->metadata_batch[0][0]);
   }
-  if (bctl->send_message) {
-    call->sending_message = 0;
+  if (stream_op->send_message) {
+    call->sending_message = false;
     grpc_byte_stream_destroy(exec_ctx, &call->sending_stream.base);
   }
-  if (bctl->send_final_op) {
-    call->sent_final_op = 0;
+  if (stream_op->send_trailing_metadata) {
+    call->sent_final_op = false;
     grpc_metadata_batch_clear(exec_ctx, &call->metadata_batch[0][1]);
   }
-  if (bctl->recv_initial_metadata) {
-    call->received_initial_metadata = 0;
+  if (stream_op->recv_initial_metadata) {
+    call->received_initial_metadata = false;
   }
-  if (bctl->recv_message) {
-    call->receiving_message = 0;
+  if (stream_op->recv_message) {
+    call->receiving_message = false;
   }
-  if (bctl->recv_final_op) {
-    call->requested_final_op = 0;
+  if (stream_op->recv_trailing_metadata) {
+    call->requested_final_op = false;
   }
   goto done;
 }
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index b4bfb92..b3ba826 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -150,17 +150,20 @@
     } else if (0 == strcmp(args->args[i].key,
                            GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL)) {
       channel->compression_options.default_level.is_set = true;
-      GPR_ASSERT(args->args[i].value.integer >= 0 &&
-                 args->args[i].value.integer < GRPC_COMPRESS_LEVEL_COUNT);
       channel->compression_options.default_level.level =
-          (grpc_compression_level)args->args[i].value.integer;
+          (grpc_compression_level)grpc_channel_arg_get_integer(
+              &args->args[i],
+              (grpc_integer_options){GRPC_COMPRESS_LEVEL_NONE,
+                                     GRPC_COMPRESS_LEVEL_NONE,
+                                     GRPC_COMPRESS_LEVEL_COUNT - 1});
     } else if (0 == strcmp(args->args[i].key,
                            GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM)) {
       channel->compression_options.default_algorithm.is_set = true;
-      GPR_ASSERT(args->args[i].value.integer >= 0 &&
-                 args->args[i].value.integer < GRPC_COMPRESS_ALGORITHMS_COUNT);
       channel->compression_options.default_algorithm.algorithm =
-          (grpc_compression_algorithm)args->args[i].value.integer;
+          (grpc_compression_algorithm)grpc_channel_arg_get_integer(
+              &args->args[i],
+              (grpc_integer_options){GRPC_COMPRESS_NONE, GRPC_COMPRESS_NONE,
+                                     GRPC_COMPRESS_ALGORITHMS_COUNT - 1});
     } else if (0 ==
                strcmp(args->args[i].key,
                       GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET)) {
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
index b459481..3273add 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -345,7 +345,6 @@
 grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
                                       gpr_timespec deadline, void *reserved) {
   grpc_event ret;
-  grpc_pollset_worker *worker = NULL;
   gpr_timespec now;
 
   GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
@@ -426,8 +425,8 @@
       gpr_mu_lock(cc->mu);
       continue;
     } else {
-      grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc),
-                                          &worker, now, iteration_deadline);
+      grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), NULL,
+                                          now, iteration_deadline);
       if (err != GRPC_ERROR_NONE) {
         gpr_mu_unlock(cc->mu);
         const char *msg = grpc_error_string(err);
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index b46ecac..91bd014 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -47,7 +47,6 @@
 #include "src/core/lib/channel/handshaker_registry.h"
 #include "src/core/lib/channel/http_client_filter.h"
 #include "src/core/lib/channel/http_server_filter.h"
-#include "src/core/lib/channel/max_age_filter.h"
 #include "src/core/lib/channel/message_size_filter.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/http/parser.h"
@@ -115,9 +114,6 @@
       GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter,
       (void *)&grpc_server_deadline_filter);
   grpc_channel_init_register_stage(
-      GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter,
-      (void *)&grpc_max_age_filter);
-  grpc_channel_init_register_stage(
       GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
       prepend_filter, (void *)&grpc_message_size_filter);
   grpc_channel_init_register_stage(
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index 0c408aa..82428c4 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -80,16 +80,18 @@
   mdb->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
 }
 
-static void lame_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                           grpc_call_element *elem,
-                                           grpc_transport_stream_op *op) {
+static void lame_start_transport_stream_op_batch(
+    grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+    grpc_transport_stream_op_batch *op) {
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  if (op->recv_initial_metadata != NULL) {
-    fill_metadata(exec_ctx, elem, op->recv_initial_metadata);
-  } else if (op->recv_trailing_metadata != NULL) {
-    fill_metadata(exec_ctx, elem, op->recv_trailing_metadata);
+  if (op->recv_initial_metadata) {
+    fill_metadata(exec_ctx, elem,
+                  op->payload->recv_initial_metadata.recv_initial_metadata);
+  } else if (op->recv_trailing_metadata) {
+    fill_metadata(exec_ctx, elem,
+                  op->payload->recv_trailing_metadata.recv_trailing_metadata);
   }
-  grpc_transport_stream_op_finish_with_failure(
+  grpc_transport_stream_op_batch_finish_with_failure(
       exec_ctx, op,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING("lame client channel"));
 }
@@ -148,7 +150,7 @@
                                  grpc_channel_element *elem) {}
 
 const grpc_channel_filter grpc_lame_filter = {
-    lame_start_transport_stream_op,
+    lame_start_transport_stream_op_batch,
     lame_start_transport_op,
     sizeof(call_data),
     init_call_elem,
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index a123c9c..191ee75 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -154,8 +154,7 @@
   grpc_completion_queue *cq_new;
 
   grpc_metadata_batch *recv_initial_metadata;
-  bool recv_idempotent_request;
-  bool recv_cacheable_request;
+  uint32_t recv_initial_metadata_flags;
   grpc_metadata_array initial_metadata;
 
   request_matcher *request_matcher;
@@ -498,13 +497,7 @@
       rc->data.batch.details->host = grpc_slice_ref_internal(calld->host);
       rc->data.batch.details->method = grpc_slice_ref_internal(calld->path);
       rc->data.batch.details->deadline = calld->deadline;
-      rc->data.batch.details->flags =
-          (calld->recv_idempotent_request
-               ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST
-               : 0) |
-          (calld->recv_cacheable_request
-               ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST
-               : 0);
+      rc->data.batch.details->flags = calld->recv_initial_metadata_flags;
       break;
     case REGISTERED_CALL:
       *rc->data.registered.deadline = calld->deadline;
@@ -632,7 +625,8 @@
       if (!grpc_slice_eq(rm->host, calld->host)) continue;
       if (!grpc_slice_eq(rm->method, calld->path)) continue;
       if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) &&
-          !calld->recv_idempotent_request) {
+          0 == (calld->recv_initial_metadata_flags &
+                GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST)) {
         continue;
       }
       finish_start_new_rpc(exec_ctx, server, elem,
@@ -649,7 +643,8 @@
       if (rm->has_host) continue;
       if (!grpc_slice_eq(rm->method, calld->path)) continue;
       if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) &&
-          !calld->recv_idempotent_request) {
+          0 == (calld->recv_initial_metadata_flags &
+                GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST)) {
         continue;
       }
       finish_start_new_rpc(exec_ctx, server, elem,
@@ -781,22 +776,25 @@
 }
 
 static void server_mutate_op(grpc_call_element *elem,
-                             grpc_transport_stream_op *op) {
+                             grpc_transport_stream_op_batch *op) {
   call_data *calld = elem->call_data;
 
-  if (op->recv_initial_metadata != NULL) {
-    GPR_ASSERT(op->recv_idempotent_request == NULL);
-    calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = &calld->server_on_recv_initial_metadata;
-    op->recv_idempotent_request = &calld->recv_idempotent_request;
-    op->recv_cacheable_request = &calld->recv_cacheable_request;
+  if (op->recv_initial_metadata) {
+    GPR_ASSERT(op->payload->recv_initial_metadata.recv_flags == NULL);
+    calld->recv_initial_metadata =
+        op->payload->recv_initial_metadata.recv_initial_metadata;
+    calld->on_done_recv_initial_metadata =
+        op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+    op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+        &calld->server_on_recv_initial_metadata;
+    op->payload->recv_initial_metadata.recv_flags =
+        &calld->recv_initial_metadata_flags;
   }
 }
 
-static void server_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                             grpc_call_element *elem,
-                                             grpc_transport_stream_op *op) {
+static void server_start_transport_stream_op_batch(
+    grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+    grpc_transport_stream_op_batch *op) {
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
   server_mutate_op(elem, op);
   grpc_call_next_op(exec_ctx, elem, op);
@@ -960,7 +958,7 @@
 }
 
 const grpc_channel_filter grpc_server_top_filter = {
-    server_start_transport_stream_op,
+    server_start_transport_stream_op_batch,
     grpc_channel_next_op,
     sizeof(call_data),
     init_call_elem,
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
index d56cb31..82c4e00 100644
--- a/src/core/lib/transport/transport.c
+++ b/src/core/lib/transport/transport.c
@@ -170,7 +170,7 @@
 void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx,
                                       grpc_transport *transport,
                                       grpc_stream *stream,
-                                      grpc_transport_stream_op *op) {
+                                      grpc_transport_stream_op_batch *op) {
   transport->vtable->perform_stream_op(exec_ctx, transport, stream, op);
 }
 
@@ -213,14 +213,23 @@
   return transport->vtable->get_endpoint(exec_ctx, transport);
 }
 
-void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
-                                                  grpc_transport_stream_op *op,
-                                                  grpc_error *error) {
-  grpc_closure_sched(exec_ctx, op->recv_message_ready, GRPC_ERROR_REF(error));
-  grpc_closure_sched(exec_ctx, op->recv_initial_metadata_ready,
-                     GRPC_ERROR_REF(error));
+void grpc_transport_stream_op_batch_finish_with_failure(
+    grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *op,
+    grpc_error *error) {
+  if (op->recv_message) {
+    grpc_closure_sched(exec_ctx, op->payload->recv_message.recv_message_ready,
+                       GRPC_ERROR_REF(error));
+  }
+  if (op->recv_initial_metadata) {
+    grpc_closure_sched(
+        exec_ctx,
+        op->payload->recv_initial_metadata.recv_initial_metadata_ready,
+        GRPC_ERROR_REF(error));
+  }
   grpc_closure_sched(exec_ctx, op->on_complete, error);
-  GRPC_ERROR_UNREF(op->cancel_error);
+  if (op->cancel_stream) {
+    GRPC_ERROR_UNREF(op->payload->cancel_stream.cancel_error);
+  }
 }
 
 typedef struct {
@@ -249,7 +258,8 @@
 typedef struct {
   grpc_closure outer_on_complete;
   grpc_closure *inner_on_complete;
-  grpc_transport_stream_op op;
+  grpc_transport_stream_op_batch op;
+  grpc_transport_stream_op_batch_payload payload;
 } made_transport_stream_op;
 
 static void destroy_made_transport_stream_op(grpc_exec_ctx *exec_ctx, void *arg,
@@ -260,13 +270,13 @@
   grpc_closure_run(exec_ctx, c, GRPC_ERROR_REF(error));
 }
 
-grpc_transport_stream_op *grpc_make_transport_stream_op(
+grpc_transport_stream_op_batch *grpc_make_transport_stream_op(
     grpc_closure *on_complete) {
-  made_transport_stream_op *op = gpr_malloc(sizeof(*op));
+  made_transport_stream_op *op = gpr_zalloc(sizeof(*op));
+  op->op.payload = &op->payload;
   grpc_closure_init(&op->outer_on_complete, destroy_made_transport_stream_op,
                     op, grpc_schedule_on_exec_ctx);
   op->inner_on_complete = on_complete;
-  memset(&op->op, 0, sizeof(op->op));
   op->op.on_complete = &op->outer_on_complete;
   return &op->op;
 }
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 950b18a..93369cc 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -109,55 +109,98 @@
                                grpc_transport_stream_stats *to);
 
 typedef struct {
+  void *extra_arg;
   grpc_closure closure;
-  void *args[2];
-} grpc_transport_private_op_data;
+} grpc_handler_private_op_data;
+
+typedef struct grpc_transport_stream_op_batch_payload
+    grpc_transport_stream_op_batch_payload;
 
 /* Transport stream op: a set of operations to perform on a transport
    against a single stream */
-typedef struct grpc_transport_stream_op {
+typedef struct grpc_transport_stream_op_batch {
   /** Should be enqueued when all requested operations (excluding recv_message
       and recv_initial_metadata which have their own closures) in a given batch
       have been completed. */
   grpc_closure *on_complete;
 
+  /** Values for the stream op (fields set are determined by flags above) */
+  grpc_transport_stream_op_batch_payload *payload;
+
   /** Is the completion of this op covered by a poller (if false: the op should
       complete independently of some pollset being polled) */
-  bool covered_by_poller;
+  bool covered_by_poller : 1;
 
-  /** Send initial metadata to the peer, from the provided metadata batch.
-      idempotent_request MUST be set if this is non-null */
-  grpc_metadata_batch *send_initial_metadata;
-  /** Iff send_initial_metadata != NULL, flags associated with
-      send_initial_metadata: a bitfield of GRPC_INITIAL_METADATA_xxx */
-  uint32_t send_initial_metadata_flags;
+  /** Send initial metadata to the peer, from the provided metadata batch. */
+  bool send_initial_metadata : 1;
 
   /** Send trailing metadata to the peer, from the provided metadata batch. */
-  grpc_metadata_batch *send_trailing_metadata;
+  bool send_trailing_metadata : 1;
 
   /** Send message data to the peer, from the provided byte stream. */
-  grpc_byte_stream *send_message;
+  bool send_message : 1;
 
   /** Receive initial metadata from the stream, into provided metadata batch. */
-  grpc_metadata_batch *recv_initial_metadata;
-  bool *recv_idempotent_request;
-  bool *recv_cacheable_request;
-  /** Should be enqueued when initial metadata is ready to be processed. */
-  grpc_closure *recv_initial_metadata_ready;
+  bool recv_initial_metadata : 1;
 
   /** Receive message data from the stream, into provided byte stream. */
-  grpc_byte_stream **recv_message;
-  /** Should be enqueued when one message is ready to be processed. */
-  grpc_closure *recv_message_ready;
+  bool recv_message : 1;
 
   /** Receive trailing metadata from the stream, into provided metadata batch.
    */
-  grpc_metadata_batch *recv_trailing_metadata;
+  bool recv_trailing_metadata : 1;
 
   /** Collect any stats into provided buffer, zero internal stat counters */
-  grpc_transport_stream_stats *collect_stats;
+  bool collect_stats : 1;
 
-  /** If != GRPC_ERROR_NONE, forcefully close this stream.
+  /** Cancel this stream with the provided error */
+  bool cancel_stream : 1;
+
+  /***************************************************************************
+   * remaining fields are initialized and used at the discretion of the
+   * current handler of the op */
+
+  grpc_handler_private_op_data handler_private;
+} grpc_transport_stream_op_batch;
+
+struct grpc_transport_stream_op_batch_payload {
+  struct {
+    grpc_metadata_batch *send_initial_metadata;
+    /** Iff send_initial_metadata != NULL, flags associated with
+        send_initial_metadata: a bitfield of GRPC_INITIAL_METADATA_xxx */
+    uint32_t send_initial_metadata_flags;
+  } send_initial_metadata;
+
+  struct {
+    grpc_metadata_batch *send_trailing_metadata;
+  } send_trailing_metadata;
+
+  struct {
+    grpc_byte_stream *send_message;
+  } send_message;
+
+  struct {
+    grpc_metadata_batch *recv_initial_metadata;
+    uint32_t *recv_flags;
+    /** Should be enqueued when initial metadata is ready to be processed. */
+    grpc_closure *recv_initial_metadata_ready;
+  } recv_initial_metadata;
+
+  struct {
+    grpc_byte_stream **recv_message;
+    /** Should be enqueued when one message is ready to be processed. */
+    grpc_closure *recv_message_ready;
+  } recv_message;
+
+  struct {
+    grpc_metadata_batch *recv_trailing_metadata;
+  } recv_trailing_metadata;
+
+  struct {
+    grpc_transport_stream_stats *collect_stats;
+  } collect_stats;
+
+  /** Forcefully close this stream.
       The HTTP2 semantics should be:
       - server side: if cancel_error has GRPC_ERROR_INT_GRPC_STATUS, and
         trailing metadata has not been sent, send trailing metadata with status
@@ -167,17 +210,13 @@
         convert to a HTTP2 error code using
         grpc_chttp2_grpc_status_to_http2_error. Send a RST_STREAM with this
         error. */
-  grpc_error *cancel_error;
+  struct {
+    grpc_error *cancel_error;
+  } cancel_stream;
 
   /* Indexes correspond to grpc_context_index enum values */
   grpc_call_context_element *context;
-
-  /***************************************************************************
-   * remaining fields are initialized and used at the discretion of the
-   * current handler of the op */
-
-  grpc_transport_private_op_data handler_private;
-} grpc_transport_stream_op;
+};
 
 /** Transport op: a set of operations to perform on a transport as a whole */
 typedef struct grpc_transport_op {
@@ -210,7 +249,7 @@
    * remaining fields are initialized and used at the discretion of the
    * transport implementation */
 
-  grpc_transport_private_op_data transport_private;
+  grpc_handler_private_op_data handler_private;
 } grpc_transport_op;
 
 /* Returns the amount of memory required to store a grpc_stream for this
@@ -250,11 +289,11 @@
                                    grpc_stream *stream,
                                    grpc_closure *then_schedule_closure);
 
-void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
-                                                  grpc_transport_stream_op *op,
-                                                  grpc_error *error);
+void grpc_transport_stream_op_batch_finish_with_failure(
+    grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *op,
+    grpc_error *error);
 
-char *grpc_transport_stream_op_string(grpc_transport_stream_op *op);
+char *grpc_transport_stream_op_batch_string(grpc_transport_stream_op_batch *op);
 char *grpc_transport_op_string(grpc_transport_op *op);
 
 /* Send a batch of operations on a transport
@@ -265,11 +304,12 @@
      transport - the transport on which to initiate the stream
      stream    - the stream on which to send the operations. This must be
                  non-NULL and previously initialized by the same transport.
-     op        - a grpc_transport_stream_op specifying the op to perform */
+     op        - a grpc_transport_stream_op_batch specifying the op to perform
+   */
 void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx,
                                       grpc_transport *transport,
                                       grpc_stream *stream,
-                                      grpc_transport_stream_op *op);
+                                      grpc_transport_stream_op_batch *op);
 
 void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx,
                                grpc_transport *transport,
@@ -301,9 +341,10 @@
 /* Allocate a grpc_transport_op, and preconfigure the on_consumed closure to
    \a on_consumed and then delete the returned transport op */
 grpc_transport_op *grpc_make_transport_op(grpc_closure *on_consumed);
-/* Allocate a grpc_transport_stream_op, and preconfigure the on_consumed closure
+/* Allocate a grpc_transport_stream_op_batch, and preconfigure the on_consumed
+   closure
    to \a on_consumed and then delete the returned transport op */
-grpc_transport_stream_op *grpc_make_transport_stream_op(
+grpc_transport_stream_op_batch *grpc_make_transport_stream_op(
     grpc_closure *on_consumed);
 
 #ifdef __cplusplus
diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h
index 6f688bf..bbb19a3 100644
--- a/src/core/lib/transport/transport_impl.h
+++ b/src/core/lib/transport/transport_impl.h
@@ -59,7 +59,8 @@
 
   /* implementation of grpc_transport_perform_stream_op */
   void (*perform_stream_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
-                            grpc_stream *stream, grpc_transport_stream_op *op);
+                            grpc_stream *stream,
+                            grpc_transport_stream_op_batch *op);
 
   /* implementation of grpc_transport_perform_op */
   void (*perform_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c
index 28360e3..3a2a793 100644
--- a/src/core/lib/transport/transport_op_string.c
+++ b/src/core/lib/transport/transport_op_string.c
@@ -71,7 +71,8 @@
   }
 }
 
-char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) {
+char *grpc_transport_stream_op_batch_string(
+    grpc_transport_stream_op_batch *op) {
   char *tmp;
   char *out;
 
@@ -81,45 +82,49 @@
   gpr_strvec_add(
       &b, gpr_strdup(op->covered_by_poller ? "[COVERED]" : "[UNCOVERED]"));
 
-  if (op->send_initial_metadata != NULL) {
+  if (op->send_initial_metadata) {
     gpr_strvec_add(&b, gpr_strdup(" "));
     gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA{"));
-    put_metadata_list(&b, *op->send_initial_metadata);
+    put_metadata_list(
+        &b, *op->payload->send_initial_metadata.send_initial_metadata);
     gpr_strvec_add(&b, gpr_strdup("}"));
   }
 
-  if (op->send_message != NULL) {
+  if (op->send_message) {
     gpr_strvec_add(&b, gpr_strdup(" "));
     gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d",
-                 op->send_message->flags, op->send_message->length);
+                 op->payload->send_message.send_message->flags,
+                 op->payload->send_message.send_message->length);
     gpr_strvec_add(&b, tmp);
   }
 
-  if (op->send_trailing_metadata != NULL) {
+  if (op->send_trailing_metadata) {
     gpr_strvec_add(&b, gpr_strdup(" "));
     gpr_strvec_add(&b, gpr_strdup("SEND_TRAILING_METADATA{"));
-    put_metadata_list(&b, *op->send_trailing_metadata);
+    put_metadata_list(
+        &b, *op->payload->send_trailing_metadata.send_trailing_metadata);
     gpr_strvec_add(&b, gpr_strdup("}"));
   }
 
-  if (op->recv_initial_metadata != NULL) {
+  if (op->recv_initial_metadata) {
     gpr_strvec_add(&b, gpr_strdup(" "));
     gpr_strvec_add(&b, gpr_strdup("RECV_INITIAL_METADATA"));
   }
 
-  if (op->recv_message != NULL) {
+  if (op->recv_message) {
     gpr_strvec_add(&b, gpr_strdup(" "));
     gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE"));
   }
 
-  if (op->recv_trailing_metadata != NULL) {
+  if (op->recv_trailing_metadata) {
     gpr_strvec_add(&b, gpr_strdup(" "));
     gpr_strvec_add(&b, gpr_strdup("RECV_TRAILING_METADATA"));
   }
 
-  if (op->cancel_error != GRPC_ERROR_NONE) {
+  if (op->cancel_stream) {
     gpr_strvec_add(&b, gpr_strdup(" "));
-    const char *msg = grpc_error_string(op->cancel_error);
+    const char *msg =
+        grpc_error_string(op->payload->cancel_stream.cancel_error);
     gpr_asprintf(&tmp, "CANCEL:%s", msg);
 
     gpr_strvec_add(&b, tmp);
@@ -204,8 +209,9 @@
 }
 
 void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
-                      grpc_call_element *elem, grpc_transport_stream_op *op) {
-  char *str = grpc_transport_stream_op_string(op);
+                      grpc_call_element *elem,
+                      grpc_transport_stream_op_batch *op) {
+  char *str = grpc_transport_stream_op_batch_string(op);
   gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str);
   gpr_free(str);
 }
diff --git a/src/core/plugin_registry/grpc_plugin_registry.c b/src/core/plugin_registry/grpc_plugin_registry.c
index 596e3b7..803a26b 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_plugin_registry.c
@@ -53,6 +53,8 @@
 extern void grpc_load_reporting_plugin_shutdown(void);
 extern void census_grpc_plugin_init(void);
 extern void census_grpc_plugin_shutdown(void);
+extern void grpc_max_age_filter_init(void);
+extern void grpc_max_age_filter_shutdown(void);
 
 void grpc_register_built_in_plugins(void) {
   grpc_register_plugin(grpc_chttp2_plugin_init,
@@ -75,4 +77,6 @@
                        grpc_load_reporting_plugin_shutdown);
   grpc_register_plugin(census_grpc_plugin_init,
                        census_grpc_plugin_shutdown);
+  grpc_register_plugin(grpc_max_age_filter_init,
+                       grpc_max_age_filter_shutdown);
 }
diff --git a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
index a05ebcb..e65fc24 100644
--- a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
@@ -53,6 +53,8 @@
 extern void grpc_lb_policy_round_robin_shutdown(void);
 extern void census_grpc_plugin_init(void);
 extern void census_grpc_plugin_shutdown(void);
+extern void grpc_max_age_filter_init(void);
+extern void grpc_max_age_filter_shutdown(void);
 
 void grpc_register_built_in_plugins(void) {
   grpc_register_plugin(grpc_chttp2_plugin_init,
@@ -75,4 +77,6 @@
                        grpc_lb_policy_round_robin_shutdown);
   grpc_register_plugin(census_grpc_plugin_init,
                        census_grpc_plugin_shutdown);
+  grpc_register_plugin(grpc_max_age_filter_init,
+                       grpc_max_age_filter_shutdown);
 }
diff --git a/src/cpp/common/channel_filter.cc b/src/cpp/common/channel_filter.cc
index 253614c..a7b3c2c 100644
--- a/src/cpp/common/channel_filter.cc
+++ b/src/cpp/common/channel_filter.cc
@@ -69,9 +69,9 @@
 
 // CallData
 
-void CallData::StartTransportStreamOp(grpc_exec_ctx *exec_ctx,
-                                      grpc_call_element *elem,
-                                      TransportStreamOp *op) {
+void CallData::StartTransportStreamOpBatch(grpc_exec_ctx *exec_ctx,
+                                           grpc_call_element *elem,
+                                           TransportStreamOpBatch *op) {
   grpc_call_next_op(exec_ctx, elem, op->op());
 }
 
diff --git a/src/cpp/common/channel_filter.h b/src/cpp/common/channel_filter.h
index 7bdb9b3..8d800b8 100644
--- a/src/cpp/common/channel_filter.h
+++ b/src/cpp/common/channel_filter.h
@@ -140,63 +140,80 @@
   grpc_transport_op *op_;  // Not owned.
 };
 
-/// A C++ wrapper for the \c grpc_transport_stream_op struct.
-class TransportStreamOp {
+/// A C++ wrapper for the \c grpc_transport_stream_op_batch struct.
+class TransportStreamOpBatch {
  public:
   /// Borrows a pointer to \a op, but does NOT take ownership.
   /// The caller must ensure that \a op continues to exist for as
-  /// long as the TransportStreamOp object does.
-  explicit TransportStreamOp(grpc_transport_stream_op *op)
+  /// long as the TransportStreamOpBatch object does.
+  explicit TransportStreamOpBatch(grpc_transport_stream_op_batch *op)
       : op_(op),
-        send_initial_metadata_(op->send_initial_metadata),
-        send_trailing_metadata_(op->send_trailing_metadata),
-        recv_initial_metadata_(op->recv_initial_metadata),
-        recv_trailing_metadata_(op->recv_trailing_metadata) {}
+        send_initial_metadata_(
+            op->send_initial_metadata
+                ? op->payload->send_initial_metadata.send_initial_metadata
+                : nullptr),
+        send_trailing_metadata_(
+            op->send_trailing_metadata
+                ? op->payload->send_trailing_metadata.send_trailing_metadata
+                : nullptr),
+        recv_initial_metadata_(
+            op->recv_initial_metadata
+                ? op->payload->recv_initial_metadata.recv_initial_metadata
+                : nullptr),
+        recv_trailing_metadata_(
+            op->recv_trailing_metadata
+                ? op->payload->recv_trailing_metadata.recv_trailing_metadata
+                : nullptr) {}
 
-  grpc_transport_stream_op *op() const { return op_; }
+  grpc_transport_stream_op_batch *op() const { return op_; }
 
   grpc_closure *on_complete() const { return op_->on_complete; }
   void set_on_complete(grpc_closure *closure) { op_->on_complete = closure; }
 
   MetadataBatch *send_initial_metadata() {
-    return op_->send_initial_metadata == nullptr ? nullptr
-                                                 : &send_initial_metadata_;
+    return op_->send_initial_metadata ? &send_initial_metadata_ : nullptr;
   }
   MetadataBatch *send_trailing_metadata() {
-    return op_->send_trailing_metadata == nullptr ? nullptr
-                                                  : &send_trailing_metadata_;
+    return op_->send_trailing_metadata ? &send_trailing_metadata_ : nullptr;
   }
   MetadataBatch *recv_initial_metadata() {
-    return op_->recv_initial_metadata == nullptr ? nullptr
-                                                 : &recv_initial_metadata_;
+    return op_->recv_initial_metadata ? &recv_initial_metadata_ : nullptr;
   }
   MetadataBatch *recv_trailing_metadata() {
-    return op_->recv_trailing_metadata == nullptr ? nullptr
-                                                  : &recv_trailing_metadata_;
+    return op_->recv_trailing_metadata ? &recv_trailing_metadata_ : nullptr;
   }
 
   uint32_t *send_initial_metadata_flags() const {
-    return &op_->send_initial_metadata_flags;
+    return op_->send_initial_metadata
+               ? &op_->payload->send_initial_metadata
+                      .send_initial_metadata_flags
+               : nullptr;
   }
 
   grpc_closure *recv_initial_metadata_ready() const {
-    return op_->recv_initial_metadata_ready;
+    return op_->recv_initial_metadata
+               ? op_->payload->recv_initial_metadata.recv_initial_metadata_ready
+               : nullptr;
   }
   void set_recv_initial_metadata_ready(grpc_closure *closure) {
-    op_->recv_initial_metadata_ready = closure;
+    op_->payload->recv_initial_metadata.recv_initial_metadata_ready = closure;
   }
 
-  grpc_byte_stream *send_message() const { return op_->send_message; }
+  grpc_byte_stream *send_message() const {
+    return op_->send_message ? op_->payload->send_message.send_message
+                             : nullptr;
+  }
   void set_send_message(grpc_byte_stream *send_message) {
-    op_->send_message = send_message;
+    op_->send_message = true;
+    op_->payload->send_message.send_message = send_message;
   }
 
   census_context *get_census_context() const {
-    return (census_context *)op_->context[GRPC_CONTEXT_TRACING].value;
+    return (census_context *)op_->payload->context[GRPC_CONTEXT_TRACING].value;
   }
 
  private:
-  grpc_transport_stream_op *op_;  // Not owned.
+  grpc_transport_stream_op_batch *op_;  // Not owned.
   MetadataBatch send_initial_metadata_;
   MetadataBatch send_trailing_metadata_;
   MetadataBatch recv_initial_metadata_;
@@ -240,9 +257,9 @@
   // TODO(roth): Find a way to avoid passing elem into these methods.
 
   /// Starts a new stream operation.
-  virtual void StartTransportStreamOp(grpc_exec_ctx *exec_ctx,
-                                      grpc_call_element *elem,
-                                      TransportStreamOp *op);
+  virtual void StartTransportStreamOpBatch(grpc_exec_ctx *exec_ctx,
+                                           grpc_call_element *elem,
+                                           TransportStreamOpBatch *op);
 
   /// Sets a pollset or pollset set.
   virtual void SetPollsetOrPollsetSet(grpc_exec_ctx *exec_ctx,
@@ -312,12 +329,12 @@
     reinterpret_cast<CallDataType *>(elem->call_data)->~CallDataType();
   }
 
-  static void StartTransportStreamOp(grpc_exec_ctx *exec_ctx,
-                                     grpc_call_element *elem,
-                                     grpc_transport_stream_op *op) {
+  static void StartTransportStreamOpBatch(grpc_exec_ctx *exec_ctx,
+                                          grpc_call_element *elem,
+                                          grpc_transport_stream_op_batch *op) {
     CallDataType *call_data = (CallDataType *)elem->call_data;
-    TransportStreamOp op_wrapper(op);
-    call_data->StartTransportStreamOp(exec_ctx, elem, &op_wrapper);
+    TransportStreamOpBatch op_wrapper(op);
+    call_data->StartTransportStreamOpBatch(exec_ctx, elem, &op_wrapper);
   }
 
   static void SetPollsetOrPollsetSet(grpc_exec_ctx *exec_ctx,
@@ -369,7 +386,7 @@
       stack_type,
       priority,
       include_filter,
-      {FilterType::StartTransportStreamOp, FilterType::StartTransportOp,
+      {FilterType::StartTransportStreamOpBatch, FilterType::StartTransportOp,
        FilterType::call_data_size, FilterType::InitCallElement,
        FilterType::SetPollsetOrPollsetSet, FilterType::DestroyCallElement,
        FilterType::channel_data_size, FilterType::InitChannelElement,
diff --git a/src/cpp/common/core_codegen.cc b/src/cpp/common/core_codegen.cc
index 36e4c89..43dffe7 100644
--- a/src/cpp/common/core_codegen.cc
+++ b/src/cpp/common/core_codegen.cc
@@ -111,6 +111,8 @@
   return ::grpc_raw_byte_buffer_create(slice, nslices);
 }
 
+grpc_slice CoreCodegen::grpc_empty_slice() { return ::grpc_empty_slice(); }
+
 grpc_slice CoreCodegen::grpc_slice_malloc(size_t length) {
   return ::grpc_slice_malloc(length);
 }
diff --git a/src/csharp/doc/grpc_csharp_public.shfbproj b/src/csharp/doc/grpc_csharp_public.shfbproj
index d9b9749..fab953d 100644
--- a/src/csharp/doc/grpc_csharp_public.shfbproj
+++ b/src/csharp/doc/grpc_csharp_public.shfbproj
@@ -18,8 +18,10 @@
     <Language>en-US</Language>
     <DocumentationSources>
       <DocumentationSource sourceFile="..\Grpc.Auth\Grpc.Auth.csproj" />
-      <DocumentationSource sourceFile="..\Grpc.Core\Grpc.Core.csproj" />
-    </DocumentationSources>
+<DocumentationSource sourceFile="..\Grpc.Core\Grpc.Core.csproj" />
+<DocumentationSource sourceFile="..\Grpc.HealthCheck\Grpc.HealthCheck.csproj" />
+<DocumentationSource sourceFile="..\Grpc.Reflection\Grpc.Reflection.csproj" />
+<DocumentationSource sourceFile="..\Grpc.Core.Testing\Grpc.Core.Testing.csproj" /></DocumentationSources>
     <BuildAssemblerVerbosity>OnlyWarningsAndErrors</BuildAssemblerVerbosity>
     <HelpFileFormat>Website</HelpFileFormat>
     <IndentHtml>False</IndentHtml>
@@ -40,12 +42,13 @@
     <HtmlHelpName>Documentation</HtmlHelpName>
     <NamespaceSummaries>
       <NamespaceSummaryItem name="Grpc.Auth" isDocumented="True">Provides OAuth2 based authentication for gRPC. &lt;c&gt;Grpc.Auth&lt;/c&gt; currently consists of a set of very lightweight wrappers and uses C# &lt;a href="https://www.nuget.org/packages/Google.Apis.Auth/"&gt;Google.Apis.Auth&lt;/a&gt; library.</NamespaceSummaryItem>
-<NamespaceSummaryItem name="Grpc.Core" isDocumented="True">Main namespace for gRPC C# functionality. Contains concepts representing both client side and server side gRPC logic.
+      <NamespaceSummaryItem name="Grpc.Core" isDocumented="True">Main namespace for gRPC C# functionality. Contains concepts representing both client side and server side gRPC logic.
 
 &lt;seealso cref="Grpc.Core.Channel"/&gt; 
 &lt;seealso cref="Grpc.Core.Server"/&gt;</NamespaceSummaryItem>
-<NamespaceSummaryItem name="Grpc.Core.Logging" isDocumented="True">Provides functionality to redirect gRPC logs to application-specified destination.</NamespaceSummaryItem>
-<NamespaceSummaryItem name="Grpc.Core.Utils" isDocumented="True">Various utilities for gRPC C#.</NamespaceSummaryItem></NamespaceSummaries>
+      <NamespaceSummaryItem name="Grpc.Core.Logging" isDocumented="True">Provides functionality to redirect gRPC logs to application-specified destination.</NamespaceSummaryItem>
+      <NamespaceSummaryItem name="Grpc.Core.Utils" isDocumented="True">Various utilities for gRPC C#.</NamespaceSummaryItem>
+    </NamespaceSummaries>
     <MissingTags>Summary, Parameter, AutoDocumentCtors, Namespace, TypeParameter, AutoDocumentDispose</MissingTags>
   </PropertyGroup>
   <!-- There are no properties for these groups.  AnyCPU needs to appear in order for Visual Studio to perform
diff --git a/src/csharp/global.json b/src/csharp/global.json
index 32ff399..f3c33ce 100644
--- a/src/csharp/global.json
+++ b/src/csharp/global.json
@@ -1,5 +1,5 @@
 {
     "sdk": {
-        "version": "1.0.0-preview2-003121"
+        "version": "1.0.0-preview2-003131"
     }
 }
\ No newline at end of file
diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc
index 7d6fb19..a99b96b 100644
--- a/src/node/ext/byte_buffer.cc
+++ b/src/node/ext/byte_buffer.cc
@@ -45,6 +45,7 @@
 namespace grpc {
 namespace node {
 
+using Nan::Callback;
 using Nan::MaybeLocal;
 
 using v8::Function;
@@ -62,7 +63,11 @@
 }
 
 namespace {
-void delete_buffer(char *data, void *hint) { delete[] data; }
+void delete_buffer(char *data, void *hint) {
+  grpc_slice *slice = static_cast<grpc_slice *>(hint);
+  grpc_slice_unref(*slice);
+  delete slice;
+}
 }
 
 Local<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
@@ -75,31 +80,15 @@
     Nan::ThrowError("Error initializing byte buffer reader.");
     return scope.Escape(Nan::Undefined());
   }
-  grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
-  size_t length = GRPC_SLICE_LENGTH(slice);
-  char *result = new char[length];
-  memcpy(result, GRPC_SLICE_START_PTR(slice), length);
-  grpc_slice_unref(slice);
-  return scope.Escape(MakeFastBuffer(
-      Nan::NewBuffer(result, length, delete_buffer, NULL).ToLocalChecked()));
+  grpc_slice *slice = new grpc_slice;
+  *slice = grpc_byte_buffer_reader_readall(&reader);
+  grpc_byte_buffer_reader_destroy(&reader);
+  char *result = reinterpret_cast<char *>(GRPC_SLICE_START_PTR(*slice));
+  size_t length = GRPC_SLICE_LENGTH(*slice);
+  Local<Value> buf =
+      Nan::NewBuffer(result, length, delete_buffer, slice).ToLocalChecked();
+  return scope.Escape(buf);
 }
 
-Local<Value> MakeFastBuffer(Local<Value> slowBuffer) {
-  Nan::EscapableHandleScope scope;
-  Local<Object> globalObj = Nan::GetCurrentContext()->Global();
-  MaybeLocal<Value> constructorValue = Nan::Get(
-      globalObj, Nan::New("Buffer").ToLocalChecked());
-  Local<Function> bufferConstructor = Local<Function>::Cast(
-      constructorValue.ToLocalChecked());
-  const int argc = 3;
-  Local<Value> consArgs[argc] = {
-    slowBuffer,
-    Nan::New<Number>(::node::Buffer::Length(slowBuffer)),
-    Nan::New<Number>(0)
-  };
-  MaybeLocal<Object> fastBuffer = Nan::NewInstance(bufferConstructor,
-                                                   argc, consArgs);
-  return scope.Escape(fastBuffer.ToLocalChecked());
-}
 }  // namespace node
 }  // namespace grpc
diff --git a/src/node/ext/byte_buffer.h b/src/node/ext/byte_buffer.h
index 55bc0ab..e8c4ac9 100644
--- a/src/node/ext/byte_buffer.h
+++ b/src/node/ext/byte_buffer.h
@@ -50,10 +50,6 @@
 /* Convert a grpc_byte_buffer to a Node.js Buffer */
 v8::Local<v8::Value> ByteBufferToBuffer(grpc_byte_buffer *buffer);
 
-/* Convert a ::node::Buffer to a fast Buffer, as defined in the Node
-   Buffer documentation */
-v8::Local<v8::Value> MakeFastBuffer(v8::Local<v8::Value> slowBuffer);
-
 }  // namespace node
 }  // namespace grpc
 
diff --git a/src/node/ext/slice.cc b/src/node/ext/slice.cc
index 98a80b3..104dd9e 100644
--- a/src/node/ext/slice.cc
+++ b/src/node/ext/slice.cc
@@ -37,7 +37,6 @@
 #include <grpc/support/alloc.h>
 
 #include "slice.h"
-#include "byte_buffer.h"
 
 namespace grpc {
 namespace node {
@@ -93,9 +92,9 @@
   Nan::EscapableHandleScope scope;
   grpc_slice *slice_ptr = new grpc_slice;
   *slice_ptr = grpc_slice_ref(slice);
-  return scope.Escape(MakeFastBuffer(Nan::NewBuffer(
+  return scope.Escape(Nan::NewBuffer(
       const_cast<char *>(reinterpret_cast<const char *>(GRPC_SLICE_START_PTR(*slice_ptr))),
-      GRPC_SLICE_LENGTH(*slice_ptr), SliceFreeCallback, slice_ptr).ToLocalChecked()));
+      GRPC_SLICE_LENGTH(*slice_ptr), SliceFreeCallback, slice_ptr).ToLocalChecked());
 }
 
 }  // namespace node
diff --git a/src/node/index.js b/src/node/index.js
index a294aad..071bfd7 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -52,42 +52,89 @@
 
 var grpc = require('./src/grpc_extension');
 
+var protobuf_js_5_common = require('./src/protobuf_js_5_common');
+var protobuf_js_6_common = require('./src/protobuf_js_6_common');
+
 grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii'));
 
 /**
- * Load a gRPC object from an existing ProtoBuf.Reflect object.
- * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.
- * @param {Object=} options Options to apply to the loaded object
+ * Load a ProtoBuf.js object as a gRPC object. The options object can provide
+ * the following options:
+ * - binaryAsBase64: deserialize bytes values as base64 strings instead of
+ *   Buffers. Defaults to false
+ * - longsAsStrings: deserialize long values as strings instead of objects.
+ *   Defaults to true
+ * - enumsAsStrings: deserialize enum values as strings instead of numbers.
+ *   Defaults to true
+ * - deprecatedArgumentOrder: Use the beta method argument order for client
+ *   methods, with optional arguments after the callback. Defaults to false.
+ *   This option is only a temporary stopgap measure to smooth an API breakage.
+ *   It is deprecated, and new code should not use it.
+ * - protobufjsVersion: Available values are 5, 6, and 'detect'. 5 and 6
+ *   respectively indicate that an object from the corresponding version of
+ *   ProtoBuf.js is provided in the value argument. If the option is 'detect',
+ *   gRPC will guess what the version is based on the structure of the value.
+ *   Defaults to 'detect'.
+ * @param {Object} value The ProtoBuf.js reflection object to load
+ * @param {Object=} options Options to apply to the loaded file
  * @return {Object<string, *>} The resulting gRPC object
  */
 exports.loadObject = function loadObject(value, options) {
-  var result = {};
-  if (value.className === 'Namespace') {
-    _.each(value.children, function(child) {
-      result[child.name] = loadObject(child, options);
-    });
-    return result;
-  } else if (value.className === 'Service') {
-    return client.makeProtobufClientConstructor(value, options);
-  } else if (value.className === 'Message' || value.className === 'Enum') {
-    return value.build();
+  options = _.defaults(options, common.defaultGrpcOptions);
+  options = _.defaults(options, {'protobufjsVersion': 'detect'});
+  var protobufjsVersion;
+  if (options.protobufjsVersion === 'detect') {
+    if (protobuf_js_6_common.isProbablyProtobufJs6(value)) {
+      protobufjsVersion = 6;
+    } else if (protobuf_js_5_common.isProbablyProtobufJs5(value)) {
+      protobufjsVersion = 5;
+    } else {
+      var error_message = 'Could not detect ProtoBuf.js version. Please ' +
+          'specify the version number with the "protobufjs_version" option';
+      throw new Error(error_message);
+    }
   } else {
-    return value;
+    protobufjsVersion = options.protobufjsVersion;
+  }
+  switch (protobufjsVersion) {
+    case 6: return protobuf_js_6_common.loadObject(value, options);
+    case 5:
+    var deprecation_message = 'Calling grpc.loadObject with an object ' +
+        'generated by ProtoBuf.js 5 is deprecated. Please upgrade to ' +
+        'ProtoBuf.js 6.';
+    common.log(grpc.logVerbosity.INFO, deprecation_message);
+    return protobuf_js_5_common.loadObject(value, options);
+    default:
+    throw new Error('Unrecognized protobufjsVersion', protobufjsVersion);
   }
 };
 
 var loadObject = exports.loadObject;
 
+function applyProtoRoot(filename, root) {
+  if (_.isString(filename)) {
+    return filename;
+  }
+  filename.root = path.resolve(filename.root) + '/';
+  root.resolvePath = function(originPath, importPath, alreadyNormalized) {
+    return ProtoBuf.util.path.resolve(filename.root,
+                                      importPath,
+                                      alreadyNormalized);
+  };
+  return filename.file;
+}
+
 /**
  * Load a gRPC object from a .proto file. The options object can provide the
  * following options:
- * - convertFieldsToCamelCase: Loads this file with that option on protobuf.js
- *   set as specified. See
- *   https://github.com/dcodeIO/protobuf.js/wiki/Advanced-options for details
+ * - convertFieldsToCamelCase: Load this file with field names in camel case
+ *   instead of their original case
  * - binaryAsBase64: deserialize bytes values as base64 strings instead of
  *   Buffers. Defaults to false
  * - longsAsStrings: deserialize long values as strings instead of objects.
  *   Defaults to true
+ * - enumsAsStrings: deserialize enum values as strings instead of numbers.
+ *   Defaults to true
  * - deprecatedArgumentOrder: Use the beta method argument order for client
  *   methods, with optional arguments after the callback. Defaults to false.
  *   This option is only a temporary stopgap measure to smooth an API breakage.
@@ -99,29 +146,17 @@
  * @return {Object<string, *>} The resulting gRPC object
  */
 exports.load = function load(filename, format, options) {
-  if (!format) {
-    format = 'proto';
-  }
-  var convertFieldsToCamelCaseOriginal = ProtoBuf.convertFieldsToCamelCase;
-  if(options && options.hasOwnProperty('convertFieldsToCamelCase')) {
-    ProtoBuf.convertFieldsToCamelCase = options.convertFieldsToCamelCase;
-  }
-  var builder;
-  try {
-    switch(format) {
-      case 'proto':
-      builder = ProtoBuf.loadProtoFile(filename);
-      break;
-      case 'json':
-      builder = ProtoBuf.loadJsonFile(filename);
-      break;
-      default:
-      throw new Error('Unrecognized format "' + format + '"');
-    }
-  } finally {
-    ProtoBuf.convertFieldsToCamelCase = convertFieldsToCamelCaseOriginal;
-  }
-  return loadObject(builder.ns, options);
+  /* Note: format is currently unused, because the API for loading a proto
+     file or a JSON file is identical in Protobuf.js 6. In the future, there is
+     still the possibility of adding other formats that would be loaded
+     differently */
+  options = _.defaults(options, common.defaultGrpcOptions);
+  options.protobufjs_version = 6;
+  var root = new ProtoBuf.Root();
+  var parse_options = {keepCase: !options.convertFieldsToCamelCase};
+  return loadObject(root.loadSync(applyProtoRoot(filename, root),
+                                  parse_options),
+                    options);
 };
 
 var log_template = _.template(
diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js
index 05f52a1..83b8a7c 100644
--- a/src/node/interop/interop_server.js
+++ b/src/node/interop/interop_server.js
@@ -228,7 +228,7 @@
     server_creds = grpc.ServerCredentials.createInsecure();
   }
   var server = new grpc.Server(options);
-  server.addProtoService(testProto.TestService.service, {
+  server.addService(testProto.TestService.service, {
     emptyCall: handleEmpty,
     unaryCall: handleUnary,
     streamingOutputCall: handleStreamingOutput,
diff --git a/src/node/performance/benchmark_server.js b/src/node/performance/benchmark_server.js
index 6abde2e..ea85029 100644
--- a/src/node/performance/benchmark_server.js
+++ b/src/node/performance/benchmark_server.js
@@ -88,6 +88,13 @@
   });
 }
 
+function makeUnaryGenericCall(response_size) {
+  var response = zeroBuffer(response_size);
+  return function unaryGenericCall(call, callback) {
+    callback(null, response);
+  };
+}
+
 function makeStreamingGenericCall(response_size) {
   var response = zeroBuffer(response_size);
   return function streamingGenericCall(call) {
@@ -129,10 +136,11 @@
   this.port = server.bind(host + ':' + port, server_creds);
   if (generic) {
     server.addService(genericService, {
+      unaryCall: makeUnaryGenericCall(response_size),
       streamingCall: makeStreamingGenericCall(response_size)
     });
   } else {
-    server.addProtoService(serviceProto.BenchmarkService.service, {
+    server.addService(serviceProto.BenchmarkService.service, {
       unaryCall: unaryCall,
       streamingCall: streamingCall
     });
diff --git a/src/node/performance/generic_service.js b/src/node/performance/generic_service.js
index ce09cc4..c936ac3 100644
--- a/src/node/performance/generic_service.js
+++ b/src/node/performance/generic_service.js
@@ -34,8 +34,17 @@
 var _ = require('lodash');
 
 module.exports = {
+  'unaryCall' : {
+    path: '/grpc.testing.BenchmarkService/UnaryCall',
+    requestStream: false,
+    responseStream: false,
+    requestSerialize: _.identity,
+    requestDeserialize: _.identity,
+    responseSerialize: _.identity,
+    responseDeserialize: _.identity
+  },
   'streamingCall' : {
-    path: '/grpc.testing/BenchmarkService',
+    path: '/grpc.testing.BenchmarkService/StreamingCall',
     requestStream: true,
     responseStream: true,
     requestSerialize: _.identity,
diff --git a/src/node/performance/worker.js b/src/node/performance/worker.js
index 030bf7d..90a9b7d 100644
--- a/src/node/performance/worker.js
+++ b/src/node/performance/worker.js
@@ -44,8 +44,8 @@
 function runServer(port, benchmark_impl) {
   var server_creds = grpc.ServerCredentials.createInsecure();
   var server = new grpc.Server();
-  server.addProtoService(serviceProto.WorkerService.service,
-                         new WorkerServiceImpl(benchmark_impl, server));
+  server.addService(serviceProto.WorkerService.service,
+                    new WorkerServiceImpl(benchmark_impl, server));
   var address = '0.0.0.0:' + port;
   server.bind(address, server_creds);
   server.start();
diff --git a/src/node/performance/worker_service_impl.js b/src/node/performance/worker_service_impl.js
index 38888a7..fa864f9 100644
--- a/src/node/performance/worker_service_impl.js
+++ b/src/node/performance/worker_service_impl.js
@@ -89,6 +89,7 @@
           default:
           call.emit('error', new Error('Unsupported PayloadConfig type' +
               setup.payload_config.payload));
+          return;
         }
         switch (setup.load_params.load) {
           case 'closed_loop':
@@ -103,6 +104,7 @@
           default:
           call.emit('error', new Error('Unsupported LoadParams type' +
               setup.load_params.load));
+          return;
         }
         stats = client.mark();
         call.write({
@@ -137,8 +139,27 @@
       switch (request.argtype) {
         case 'setup':
         console.log('ServerConfig %j', request.setup);
+        var setup = request.setup;
+        var resp_size, generic;
+        if (setup.payload_config) {
+          switch (setup.payload_config.payload) {
+            case 'bytebuf_params':
+            resp_size = setup.payload_config.bytebuf_params.resp_size;
+            generic = true;
+            break;
+            case 'simple_params':
+            resp_size = setup.payload_config.simple_params.resp_size;
+            generic = false;
+            break;
+            default:
+            call.emit('error', new Error('Unsupported PayloadConfig type' +
+                setup.payload_config.payload));
+            return;
+          }
+        }
         server = new BenchmarkServer('[::]', request.setup.port,
-                                     request.setup.security_params);
+                                     request.setup.security_params,
+                                     generic, resp_size);
         server.on('started', function() {
           stats = server.mark();
           call.write({
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 44081a3..1aaf35c 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -780,6 +780,8 @@
     _.assign(Client.prototype[name], attrs);
   });
 
+  Client.service = methods;
+
   return Client;
 };
 
@@ -823,26 +825,6 @@
 };
 
 /**
- * Creates a constructor for clients for the given service
- * @param {ProtoBuf.Reflect.Service} service The service to generate a client
- *     for
- * @param {Object=} options Options to apply to the client
- * @return {function(string, Object)} New client constructor
- */
-exports.makeProtobufClientConstructor =  function(service, options) {
-  var method_attrs = common.getProtobufServiceAttrs(service, options);
-  if (!options) {
-    options = {deprecatedArgumentOrder: false};
-  }
-  var Client = exports.makeClientConstructor(
-      method_attrs, common.fullyQualifiedName(service),
-      options);
-  Client.service = service;
-  Client.service.grpc_options = options;
-  return Client;
-};
-
-/**
  * Map of status code names to status codes
  */
 exports.status = grpc.status;
diff --git a/src/node/src/common.js b/src/node/src/common.js
index a0fe448..757969d 100644
--- a/src/node/src/common.js
+++ b/src/node/src/common.js
@@ -42,74 +42,6 @@
 var _ = require('lodash');
 
 /**
- * Get a function that deserializes a specific type of protobuf.
- * @param {function()} cls The constructor of the message type to deserialize
- * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings
- *     instead of Buffers. Defaults to false
- * @param {bool=} longsAsStrings Deserialize long values as strings instead of
- *     objects. Defaults to true
- * @return {function(Buffer):cls} The deserialization function
- */
-exports.deserializeCls = function deserializeCls(cls, binaryAsBase64,
-                                                 longsAsStrings) {
-  if (binaryAsBase64 === undefined || binaryAsBase64 === null) {
-    binaryAsBase64 = false;
-  }
-  if (longsAsStrings === undefined || longsAsStrings === null) {
-    longsAsStrings = true;
-  }
-  /**
-   * Deserialize a buffer to a message object
-   * @param {Buffer} arg_buf The buffer to deserialize
-   * @return {cls} The resulting object
-   */
-  return function deserialize(arg_buf) {
-    // Convert to a native object with binary fields as Buffers (first argument)
-    // and longs as strings (second argument)
-    return cls.decode(arg_buf).toRaw(binaryAsBase64, longsAsStrings);
-  };
-};
-
-var deserializeCls = exports.deserializeCls;
-
-/**
- * Get a function that serializes objects to a buffer by protobuf class.
- * @param {function()} Cls The constructor of the message type to serialize
- * @return {function(Cls):Buffer} The serialization function
- */
-exports.serializeCls = function serializeCls(Cls) {
-  /**
-   * Serialize an object to a Buffer
-   * @param {Object} arg The object to serialize
-   * @return {Buffer} The serialized object
-   */
-  return function serialize(arg) {
-    return new Buffer(new Cls(arg).encode().toBuffer());
-  };
-};
-
-var serializeCls = exports.serializeCls;
-
-/**
- * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value.
- * @param {ProtoBuf.Reflect.Namespace} value The value to get the name of
- * @return {string} The fully qualified name of the value
- */
-exports.fullyQualifiedName = function fullyQualifiedName(value) {
-  if (value === null || value === undefined) {
-    return '';
-  }
-  var name = value.name;
-  var parent_name = fullyQualifiedName(value.parent);
-  if (parent_name !== '') {
-    name = parent_name + '.' + name;
-  }
-  return name;
-};
-
-var fullyQualifiedName = exports.fullyQualifiedName;
-
-/**
  * Wrap a function to pass null-like values through without calling it. If no
  * function is given, just uses the identity;
  * @param {?function} func The function to wrap
@@ -128,44 +60,6 @@
 };
 
 /**
- * Return a map from method names to method attributes for the service.
- * @param {ProtoBuf.Reflect.Service} service The service to get attributes for
- * @param {Object=} options Options to apply to these attributes
- * @return {Object} The attributes map
- */
-exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
-                                                                   options) {
-  var prefix = '/' + fullyQualifiedName(service) + '/';
-  var binaryAsBase64, longsAsStrings;
-  if (options) {
-    binaryAsBase64 = options.binaryAsBase64;
-    longsAsStrings = options.longsAsStrings;
-  }
-  /* This slightly awkward construction is used to make sure we only use
-     lodash@3.10.1-compatible functions. A previous version used
-     _.fromPairs, which would be cleaner, but was introduced in lodash
-     version 4 */
-  return _.zipObject(_.map(service.children, function(method) {
-    return _.camelCase(method.name);
-  }), _.map(service.children, function(method) {
-    return {
-      originalName: method.name,
-      path: prefix + method.name,
-      requestStream: method.requestStream,
-      responseStream: method.responseStream,
-      requestType: method.resolvedRequestType,
-      responseType: method.resolvedResponseType,
-      requestSerialize: serializeCls(method.resolvedRequestType.build()),
-      requestDeserialize: deserializeCls(method.resolvedRequestType.build(),
-                                         binaryAsBase64, longsAsStrings),
-      responseSerialize: serializeCls(method.resolvedResponseType.build()),
-      responseDeserialize: deserializeCls(method.resolvedResponseType.build(),
-                                          binaryAsBase64, longsAsStrings)
-    };
-  }));
-};
-
-/**
  * The logger object for the gRPC module. Defaults to console.
  */
 exports.logger = console;
@@ -185,3 +79,14 @@
     exports.logger.error(message);
   }
 };
+
+/**
+ * Default options for loading proto files into gRPC
+ */
+exports.defaultGrpcOptions = {
+  convertFieldsToCamelCase: false,
+  binaryAsBase64: false,
+  longsAsStrings: true,
+  enumsAsStrings: true,
+  deprecatedArgumentOrder: false
+};
diff --git a/src/node/src/protobuf_js_5_common.js b/src/node/src/protobuf_js_5_common.js
new file mode 100644
index 0000000..62cf2f4
--- /dev/null
+++ b/src/node/src/protobuf_js_5_common.js
@@ -0,0 +1,181 @@
+/*
+ *
+ * Copyright 2017, 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.
+ *
+ */
+
+'use strict';
+
+var _ = require('lodash');
+var client = require('./client');
+
+/**
+ * Get a function that deserializes a specific type of protobuf.
+ * @param {function()} cls The constructor of the message type to deserialize
+ * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings
+ *     instead of Buffers. Defaults to false
+ * @param {bool=} longsAsStrings Deserialize long values as strings instead of
+ *     objects. Defaults to true
+ * @return {function(Buffer):cls} The deserialization function
+ */
+exports.deserializeCls = function deserializeCls(cls, binaryAsBase64,
+                                                 longsAsStrings) {
+  /**
+   * Deserialize a buffer to a message object
+   * @param {Buffer} arg_buf The buffer to deserialize
+   * @return {cls} The resulting object
+   */
+  return function deserialize(arg_buf) {
+    // Convert to a native object with binary fields as Buffers (first argument)
+    // and longs as strings (second argument)
+    return cls.decode(arg_buf).toRaw(binaryAsBase64, longsAsStrings);
+  };
+};
+
+var deserializeCls = exports.deserializeCls;
+
+/**
+ * Get a function that serializes objects to a buffer by protobuf class.
+ * @param {function()} Cls The constructor of the message type to serialize
+ * @return {function(Cls):Buffer} The serialization function
+ */
+exports.serializeCls = function serializeCls(Cls) {
+  /**
+   * Serialize an object to a Buffer
+   * @param {Object} arg The object to serialize
+   * @return {Buffer} The serialized object
+   */
+  return function serialize(arg) {
+    return new Buffer(new Cls(arg).encode().toBuffer());
+  };
+};
+
+var serializeCls = exports.serializeCls;
+
+/**
+ * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value.
+ * @param {ProtoBuf.Reflect.Namespace} value The value to get the name of
+ * @return {string} The fully qualified name of the value
+ */
+exports.fullyQualifiedName = function fullyQualifiedName(value) {
+  if (value === null || value === undefined) {
+    return '';
+  }
+  var name = value.name;
+  var parent_name = fullyQualifiedName(value.parent);
+  if (parent_name !== '') {
+    name = parent_name + '.' + name;
+  }
+  return name;
+};
+
+var fullyQualifiedName = exports.fullyQualifiedName;
+
+/**
+ * Return a map from method names to method attributes for the service.
+ * @param {ProtoBuf.Reflect.Service} service The service to get attributes for
+ * @param {Object=} options Options to apply to these attributes
+ * @return {Object} The attributes map
+ */
+exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
+                                                                   options) {
+  var prefix = '/' + fullyQualifiedName(service) + '/';
+  var binaryAsBase64, longsAsStrings;
+  if (options) {
+    binaryAsBase64 = options.binaryAsBase64;
+    longsAsStrings = options.longsAsStrings;
+  }
+  /* This slightly awkward construction is used to make sure we only use
+     lodash@3.10.1-compatible functions. A previous version used
+     _.fromPairs, which would be cleaner, but was introduced in lodash
+     version 4 */
+  return _.zipObject(_.map(service.children, function(method) {
+    return _.camelCase(method.name);
+  }), _.map(service.children, function(method) {
+    return {
+      originalName: method.name,
+      path: prefix + method.name,
+      requestStream: method.requestStream,
+      responseStream: method.responseStream,
+      requestType: method.resolvedRequestType,
+      responseType: method.resolvedResponseType,
+      requestSerialize: serializeCls(method.resolvedRequestType.build()),
+      requestDeserialize: deserializeCls(method.resolvedRequestType.build(),
+                                         binaryAsBase64, longsAsStrings),
+      responseSerialize: serializeCls(method.resolvedResponseType.build()),
+      responseDeserialize: deserializeCls(method.resolvedResponseType.build(),
+                                          binaryAsBase64, longsAsStrings)
+    };
+  }));
+};
+
+var getProtobufServiceAttrs = exports.getProtobufServiceAttrs;
+
+/**
+ * Load a gRPC object from an existing ProtoBuf.Reflect object.
+ * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.
+ * @param {Object=} options Options to apply to the loaded object
+ * @return {Object<string, *>} The resulting gRPC object
+ */
+exports.loadObject = function loadObject(value, options) {
+  var result = {};
+  if (!value) {
+    return value;
+  }
+  if (value.hasOwnProperty('ns')) {
+    return loadObject(value.ns, options);
+  }
+  if (value.className === 'Namespace') {
+    _.each(value.children, function(child) {
+      result[child.name] = loadObject(child, options);
+    });
+    return result;
+  } else if (value.className === 'Service') {
+    return client.makeClientConstructor(getProtobufServiceAttrs(value, options),
+                                        options);
+  } else if (value.className === 'Message' || value.className === 'Enum') {
+    return value.build();
+  } else {
+    return value;
+  }
+};
+
+/**
+ * The primary purpose of this method is to distinguish between reflection
+ * objects from different versions of ProtoBuf.js. This is just a heuristic,
+ * checking for properties that are (currently) specific to this version of
+ * ProtoBuf.js
+ * @param {Object} obj The object to check
+ * @return {boolean} Whether the object appears to be a Protobuf.js 5
+ *   ReflectionObject
+ */
+exports.isProbablyProtobufJs5 = function isProbablyProtobufJs5(obj) {
+  return _.isArray(obj.children) && (typeof obj.build === 'function');
+};
diff --git a/src/node/src/protobuf_js_6_common.js b/src/node/src/protobuf_js_6_common.js
new file mode 100644
index 0000000..00f11f2
--- /dev/null
+++ b/src/node/src/protobuf_js_6_common.js
@@ -0,0 +1,170 @@
+/*
+ *
+ * Copyright 2017, 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.
+ *
+ */
+
+'use strict';
+
+var _ = require('lodash');
+var client = require('./client');
+
+/**
+ * Get a function that deserializes a specific type of protobuf.
+ * @param {function()} cls The constructor of the message type to deserialize
+ * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings
+ *     instead of Buffers. Defaults to false
+ * @param {bool=} longsAsStrings Deserialize long values as strings instead of
+ *     objects. Defaults to true
+ * @return {function(Buffer):cls} The deserialization function
+ */
+exports.deserializeCls = function deserializeCls(cls, options) {
+  var conversion_options = {
+    defaults: true,
+    bytes: options.binaryAsBase64 ? String : Buffer,
+    longs: options.longsAsStrings ? String : null,
+    enums: options.enumsAsStrings ? String : null,
+    oneofs: true
+  };
+  /**
+   * Deserialize a buffer to a message object
+   * @param {Buffer} arg_buf The buffer to deserialize
+   * @return {cls} The resulting object
+   */
+  return function deserialize(arg_buf) {
+    return cls.decode(arg_buf).toObject(conversion_options);
+  };
+};
+
+var deserializeCls = exports.deserializeCls;
+
+/**
+ * Get a function that serializes objects to a buffer by protobuf class.
+ * @param {function()} Cls The constructor of the message type to serialize
+ * @return {function(Cls):Buffer} The serialization function
+ */
+exports.serializeCls = function serializeCls(cls) {
+  /**
+   * Serialize an object to a Buffer
+   * @param {Object} arg The object to serialize
+   * @return {Buffer} The serialized object
+   */
+  return function serialize(arg) {
+    var message = cls.fromObject(arg);
+    return cls.encode(message).finish();
+  };
+};
+
+var serializeCls = exports.serializeCls;
+
+/**
+ * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value.
+ * @param {ProtoBuf.ReflectionObject} value The value to get the name of
+ * @return {string} The fully qualified name of the value
+ */
+exports.fullyQualifiedName = function fullyQualifiedName(value) {
+  if (value === null || value === undefined) {
+    return '';
+  }
+  var name = value.name;
+  var parent_fqn = fullyQualifiedName(value.parent);
+  if (parent_fqn !== '') {
+    name = parent_fqn + '.' + name;
+  }
+  return name;
+};
+
+var fullyQualifiedName = exports.fullyQualifiedName;
+
+/**
+ * Return a map from method names to method attributes for the service.
+ * @param {ProtoBuf.Service} service The service to get attributes for
+ * @param {Object=} options Options to apply to these attributes
+ * @return {Object} The attributes map
+ */
+exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
+                                                                   options) {
+  var prefix = '/' + fullyQualifiedName(service) + '/';
+  service.resolveAll();
+  return _.zipObject(_.map(service.methods, function(method) {
+    return _.camelCase(method.name);
+  }), _.map(service.methods, function(method) {
+    return {
+      originalName: method.name,
+      path: prefix + method.name,
+      requestStream: !!method.requestStream,
+      responseStream: !!method.responseStream,
+      requestType: method.resolvedRequestType,
+      responseType: method.resolvedResponseType,
+      requestSerialize: serializeCls(method.resolvedRequestType),
+      requestDeserialize: deserializeCls(method.resolvedRequestType, options),
+      responseSerialize: serializeCls(method.resolvedResponseType),
+      responseDeserialize: deserializeCls(method.resolvedResponseType, options)
+    };
+  }));
+};
+
+var getProtobufServiceAttrs = exports.getProtobufServiceAttrs;
+
+exports.loadObject = function loadObject(value, options) {
+  var result = {};
+  if (!value) {
+    return value;
+  }
+  if (value.hasOwnProperty('methods')) {
+    // It's a service object
+    var service_attrs = getProtobufServiceAttrs(value, options);
+    return client.makeClientConstructor(service_attrs);
+  }
+
+  if (value.hasOwnProperty('nested')) {
+    // It's a namespace or root object
+    _.each(value.nested, function(nested, name) {
+      result[name] = loadObject(nested, options);
+    });
+    return result;
+  }
+
+  // Otherwise, it's not something we need to change
+  return value;
+};
+
+/**
+ * The primary purpose of this method is to distinguish between reflection
+ * objects from different versions of ProtoBuf.js. This is just a heuristic,
+ * checking for properties that are (currently) specific to this version of
+ * ProtoBuf.js
+ * @param {Object} obj The object to check
+ * @return {boolean} Whether the object appears to be a Protobuf.js 6
+ *   ReflectionObject
+ */
+exports.isProbablyProtobufJs6 = function isProbablyProtobufJs6(obj) {
+  return (typeof obj.root === 'object') && (typeof obj.resolve === 'function');
+};
diff --git a/src/node/src/server.js b/src/node/src/server.js
index bdb4a56..3450abe 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -781,17 +781,31 @@
 
 /**
  * Add a proto service to the server, with a corresponding implementation
+ * @deprecated Use grpc.load and Server#addService instead
  * @param {Protobuf.Reflect.Service} service The proto service descriptor
  * @param {Object<String, function>} implementation Map of method names to
  *     method implementation for the provided service.
  */
 Server.prototype.addProtoService = function(service, implementation) {
   var options;
-  if (service.grpc_options) {
-    options = service.grpc_options;
+  var protobuf_js_5_common = require('./protobuf_js_5_common');
+  var protobuf_js_6_common = require('./protobuf_js_6_common');
+  common.log(grpc.logVerbosity.INFO,
+             'Server#addProtoService is deprecated. Use addService instead');
+  if (protobuf_js_5_common.isProbablyProtobufJs5(service)) {
+    options = _.defaults(service.grpc_options, common.defaultGrpcOptions);
+    this.addService(
+        protobuf_js_5_common.getProtobufServiceAttrs(service, options),
+        implementation);
+  } else if (protobuf_js_6_common.isProbablyProtobufJs6(service)) {
+    options = _.defaults(service.grpc_options, common.defaultGrpcOptions);
+    this.addService(
+        protobuf_js_6_common.getProtobufServiceAttrs(service, options),
+        implementation);
+  } else {
+    // We assume that this is a service attributes object
+    this.addService(service, implementation);
   }
-  this.addService(common.getProtobufServiceAttrs(service, options),
-                  implementation);
 };
 
 /**
diff --git a/src/node/stress/metrics_server.js b/src/node/stress/metrics_server.js
index 3ab4b4c..b3f939e 100644
--- a/src/node/stress/metrics_server.js
+++ b/src/node/stress/metrics_server.js
@@ -63,7 +63,7 @@
 
 function MetricsServer(port) {
   var server = new grpc.Server();
-  server.addProtoService(metrics.MetricsService.service, {
+  server.addService(metrics.MetricsService.service, {
     getGauge: _.bind(getGauge, this),
     getAllGauges: _.bind(getAllGauges, this)
   });
diff --git a/src/node/test/common_test.js b/src/node/test/common_test.js
index c57b738..e1ce864 100644
--- a/src/node/test/common_test.js
+++ b/src/node/test/common_test.js
@@ -34,17 +34,26 @@
 'use strict';
 
 var assert = require('assert');
+var _ = require('lodash');
 
-var common = require('../src/common.js');
+var common = require('../src/common');
+var protobuf_js_6_common = require('../src/protobuf_js_6_common');
+
+var serializeCls = protobuf_js_6_common.serializeCls;
+var deserializeCls = protobuf_js_6_common.deserializeCls;
 
 var ProtoBuf = require('protobufjs');
 
-var messages_proto = ProtoBuf.loadProtoFile(
-    __dirname + '/test_messages.proto').build();
+var messages_proto = new ProtoBuf.Root();
+messages_proto = messages_proto.loadSync(
+    __dirname + '/test_messages.proto', {keepCase: true}).resolveAll();
+
+var default_options = common.defaultGrpcOptions;
 
 describe('Proto message long int serialize and deserialize', function() {
-  var longSerialize = common.serializeCls(messages_proto.LongValues);
-  var longDeserialize = common.deserializeCls(messages_proto.LongValues);
+  var longSerialize = serializeCls(messages_proto.LongValues);
+  var longDeserialize = deserializeCls(messages_proto.LongValues,
+                                       default_options);
   var pos_value = '314159265358979';
   var neg_value = '-27182818284590';
   it('should preserve positive int64 values', function() {
@@ -88,8 +97,9 @@
                        neg_value);
   });
   it('should deserialize as a number with the right option set', function() {
-    var longNumDeserialize = common.deserializeCls(messages_proto.LongValues,
-                                                   false, false);
+    var num_options = _.defaults({longsAsStrings: false}, default_options);
+    var longNumDeserialize = deserializeCls(messages_proto.LongValues,
+                                            num_options);
     var serialized = longSerialize({int_64: pos_value});
     assert.strictEqual(typeof longDeserialize(serialized).int_64, 'string');
     /* With the longsAsStrings option disabled, long values are represented as
@@ -98,11 +108,12 @@
   });
 });
 describe('Proto message bytes serialize and deserialize', function() {
-  var sequenceSerialize = common.serializeCls(messages_proto.SequenceValues);
-  var sequenceDeserialize = common.deserializeCls(
-      messages_proto.SequenceValues);
-  var sequenceBase64Deserialize = common.deserializeCls(
-      messages_proto.SequenceValues, true);
+  var sequenceSerialize = serializeCls(messages_proto.SequenceValues);
+  var sequenceDeserialize = deserializeCls(
+      messages_proto.SequenceValues, default_options);
+  var b64_options = _.defaults({binaryAsBase64: true}, default_options);
+  var sequenceBase64Deserialize = deserializeCls(
+      messages_proto.SequenceValues, b64_options);
   var buffer_val = new Buffer([0x69, 0xb7]);
   var base64_val = 'abc=';
   it('should preserve a buffer', function() {
@@ -120,19 +131,73 @@
     var deserialized = sequenceBase64Deserialize(serialized);
     assert.strictEqual(deserialized.bytes_field, base64_val);
   });
-  /* The next two tests are specific tests to verify that issue
-   * https://github.com/grpc/grpc/issues/5174 has been fixed. They are skipped
-   * because they will not pass until a protobuf.js release has been published
-   * with a fix for https://github.com/dcodeIO/protobuf.js/issues/390 */
-  it.skip('should serialize a repeated field as packed by default', function() {
-    var expected_serialize = new Buffer([0x12, 0x01, 0x01, 0x0a]);
+  it('should serialize a repeated field as packed by default', function() {
+    var expected_serialize = new Buffer([0x12, 0x01, 0x0a]);
     var serialized = sequenceSerialize({repeated_field: [10]});
     assert.strictEqual(expected_serialize.compare(serialized), 0);
   });
-  it.skip('should deserialize packed or unpacked repeated', function() {
-    var serialized = new Buffer([0x12, 0x01, 0x01, 0x0a]);
+  it('should deserialize packed or unpacked repeated', function() {
+    var expectedDeserialize = {
+      bytes_field: new Buffer(''),
+      repeated_field: [10]
+    };
+    var packedSerialized = new Buffer([0x12, 0x01, 0x0a]);
+    var unpackedSerialized = new Buffer([0x10, 0x0a]);
+    var packedDeserialized;
+    var unpackedDeserialized;
     assert.doesNotThrow(function() {
-      sequenceDeserialize(serialized);
+      packedDeserialized = sequenceDeserialize(packedSerialized);
     });
+    assert.doesNotThrow(function() {
+      unpackedDeserialized = sequenceDeserialize(unpackedSerialized);
+    });
+    assert.deepEqual(packedDeserialized, expectedDeserialize);
+    assert.deepEqual(unpackedDeserialized, expectedDeserialize);
+  });
+});
+describe('Proto message oneof serialize and deserialize', function() {
+  var oneofSerialize = serializeCls(messages_proto.OneOfValues);
+  var oneofDeserialize = deserializeCls(
+      messages_proto.OneOfValues, default_options);
+  it('Should have idempotent round trips', function() {
+    var test_message = {oneof_choice: 'int_choice', int_choice: 5};
+    var serialized1 = oneofSerialize(test_message);
+    var deserialized1 = oneofDeserialize(serialized1);
+    assert.equal(deserialized1.int_choice, 5);
+    var serialized2 = oneofSerialize(deserialized1);
+    var deserialized2 = oneofDeserialize(serialized2);
+    assert.deepEqual(deserialized1, deserialized2);
+  });
+  it('Should emit a property indicating which field was chosen', function() {
+    var test_message1 = {oneof_choice: 'int_choice', int_choice: 5};
+    var serialized1 = oneofSerialize(test_message1);
+    var deserialized1 = oneofDeserialize(serialized1);
+    assert.equal(deserialized1.oneof_choice, 'int_choice');
+    var test_message2 = {oneof_choice: 'string_choice', string_choice: 'abc'};
+    var serialized2 = oneofSerialize(test_message2);
+    var deserialized2 = oneofDeserialize(serialized2);
+    assert.equal(deserialized2.oneof_choice, 'string_choice');
+  });
+});
+describe('Proto message enum serialize and deserialize', function() {
+  var enumSerialize = serializeCls(messages_proto.EnumValues);
+  var enumDeserialize = deserializeCls(
+      messages_proto.EnumValues, default_options);
+  var enumIntOptions = _.defaults({enumsAsStrings: false}, default_options);
+  var enumIntDeserialize = deserializeCls(
+      messages_proto.EnumValues, enumIntOptions);
+  it('Should accept both names and numbers', function() {
+    var nameSerialized = enumSerialize({enum_value: 'ONE'});
+    var numberSerialized = enumSerialize({enum_value: 1});
+    assert.strictEqual(messages_proto.TestEnum.ONE, 1);
+    assert.deepEqual(enumDeserialize(nameSerialized),
+                     enumDeserialize(numberSerialized));
+  });
+  it('Should deserialize as a string the enumsAsStrings option', function() {
+    var serialized = enumSerialize({enum_value: 'TWO'});
+    var nameDeserialized = enumDeserialize(serialized);
+    var numberDeserialized = enumIntDeserialize(serialized);
+    assert.deepEqual(nameDeserialized, {enum_value: 'TWO'});
+    assert.deepEqual(numberDeserialized, {enum_value: 2});
   });
 });
diff --git a/src/node/test/credentials_test.js b/src/node/test/credentials_test.js
index 305843f..b66b4bf 100644
--- a/src/node/test/credentials_test.js
+++ b/src/node/test/credentials_test.js
@@ -228,7 +228,7 @@
   before(function() {
     var proto = grpc.load(__dirname + '/test_service.proto');
     server = new grpc.Server();
-    server.addProtoService(proto.TestService.service, {
+    server.addService(proto.TestService.service, {
       unary: function(call, cb) {
         call.sendMetadata(call.metadata);
         cb(null, {});
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 1d73956..783028f 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -34,19 +34,22 @@
 'use strict';
 
 var assert = require('assert');
+var _ = require('lodash');
 
 var surface_client = require('../src/client.js');
+var common = require('../src/common');
 
 var ProtoBuf = require('protobufjs');
 
 var grpc = require('..');
 
-var math_proto = ProtoBuf.loadProtoFile(__dirname +
-    '/../../proto/math/math.proto');
+var math_proto = new ProtoBuf.Root();
+math_proto = math_proto.loadSync(__dirname +
+    '/../../proto/math/math.proto', {keepCase: true});
 
 var mathService = math_proto.lookup('math.Math');
-
-var _ = require('lodash');
+var mathServiceAttrs = grpc.loadObject(
+    mathService, common.defaultGrpcOptions).service;
 
 /**
  * This is used for testing functions with multiple asynchronous calls that
@@ -87,11 +90,6 @@
       grpc.load(__dirname + '/test_service.json', 'json');
     });
   });
-  it('Should fail to load a file with an unknown format', function() {
-    assert.throws(function() {
-      grpc.load(__dirname + '/test_service.proto', 'fake_format');
-    });
-  });
 });
 describe('surface Server', function() {
   var server;
@@ -132,15 +130,40 @@
   afterEach(function() {
     server.forceShutdown();
   });
-  it('Should succeed with a single service', function() {
+  it('Should succeed with a single proto service', function() {
     assert.doesNotThrow(function() {
       server.addProtoService(mathService, dummyImpls);
     });
   });
+  it('Should succeed with a single service attributes object', function() {
+    assert.doesNotThrow(function() {
+      server.addProtoService(mathServiceAttrs, dummyImpls);
+    });
+  });
+});
+describe('Server.prototype.addService', function() {
+  var server;
+  var dummyImpls = {
+    'div': function() {},
+    'divMany': function() {},
+    'fib': function() {},
+    'sum': function() {}
+  };
+  beforeEach(function() {
+    server = new grpc.Server();
+  });
+  afterEach(function() {
+    server.forceShutdown();
+  });
+  it('Should succeed with a single service', function() {
+    assert.doesNotThrow(function() {
+      server.addService(mathServiceAttrs, dummyImpls);
+    });
+  });
   it('Should fail with conflicting method names', function() {
-    server.addProtoService(mathService, dummyImpls);
+    server.addService(mathServiceAttrs, dummyImpls);
     assert.throws(function() {
-      server.addProtoService(mathService, dummyImpls);
+      server.addService(mathServiceAttrs, dummyImpls);
     });
   });
   it('Should allow method names as originally written', function() {
@@ -172,15 +195,15 @@
   it('Should fail if the server has been started', function() {
     server.start();
     assert.throws(function() {
-      server.addProtoService(mathService, dummyImpls);
+      server.addService(mathServiceAttrs, dummyImpls);
     });
   });
   describe('Default handlers', function() {
     var client;
     beforeEach(function() {
-      server.addProtoService(mathService, {});
+      server.addService(mathServiceAttrs, {});
       var port = server.bind('localhost:0', server_insecure_creds);
-      var Client = surface_client.makeProtobufClientConstructor(mathService);
+      var Client = grpc.loadObject(mathService);
       client = new Client('localhost:' + port,
                           grpc.credentials.createInsecure());
       server.start();
@@ -252,7 +275,7 @@
     server = new grpc.Server();
     port = server.bind('localhost:0', grpc.ServerCredentials.createInsecure());
     server.start();
-    Client = surface_client.makeProtobufClientConstructor(mathService);
+    Client = grpc.loadObject(mathService);
   });
   beforeEach(function() {
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
@@ -309,16 +332,18 @@
   var server;
   var client;
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/echo_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/echo_service.proto',
+                                         {keepCase: true});
     var echo_service = test_proto.lookup('EchoService');
+    var Client = grpc.loadObject(echo_service);
     server = new grpc.Server();
-    server.addProtoService(echo_service, {
+    server.addService(Client.service, {
       echo: function(call, callback) {
         callback(null, call.request);
       }
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    var Client = surface_client.makeProtobufClientConstructor(echo_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
@@ -432,10 +457,13 @@
   var server;
   var metadata;
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
+                                         {keepCase: true});
     var test_service = test_proto.lookup('TestService');
+    var Client = grpc.loadObject(test_service);
     server = new grpc.Server();
-    server.addProtoService(test_service, {
+    server.addService(Client.service, {
       unary: function(call, cb) {
         call.sendMetadata(call.metadata);
         cb(null, {});
@@ -460,7 +488,6 @@
       }
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    var Client = surface_client.makeProtobufClientConstructor(test_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
     metadata = new grpc.Metadata();
@@ -533,7 +560,9 @@
   var client;
   var badArg = new Buffer([0xFF]);
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
+                                         {keepCase: true});
     var test_service = test_proto.lookup('TestService');
     var malformed_test_service = {
       unary: {
@@ -591,7 +620,7 @@
       }
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    var Client = surface_client.makeProtobufClientConstructor(test_service);
+    var Client = grpc.loadObject(test_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
@@ -640,7 +669,9 @@
   var client;
   var server;
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
+                                         {keepCase: true});
     var test_service = test_proto.lookup('TestService');
     var malformed_test_service = {
       unary: {
@@ -698,7 +729,7 @@
       }
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    var Client = surface_client.makeProtobufClientConstructor(test_service);
+    var Client = grpc.loadObject(test_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
@@ -747,12 +778,15 @@
   var server;
   var port;
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
+                                         {keepCase: true});
     test_service = test_proto.lookup('TestService');
+    Client = grpc.loadObject(test_service);
     server = new grpc.Server();
     var trailer_metadata = new grpc.Metadata();
     trailer_metadata.add('trailer-present', 'yes');
-    server.addProtoService(test_service, {
+    server.addService(Client.service, {
       unary: function(call, cb) {
         var req = call.request;
         if (req.error) {
@@ -812,7 +846,6 @@
       }
     });
     port = server.bind('localhost:0', server_insecure_creds);
-    Client = surface_client.makeProtobufClientConstructor(test_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
@@ -1093,17 +1126,19 @@
   var client;
   var server;
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
+                                         {keepCase: true});
     test_service = test_proto.lookup('TestService');
     server = new grpc.Server();
-    server.addProtoService(test_service, {
+    Client = grpc.loadObject(test_service);
+    server.addService(Client.service, {
       unary: function(call) {},
       clientStream: function(stream) {},
       serverStream: function(stream) {},
       bidiStream: function(stream) {}
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    Client = surface_client.makeProtobufClientConstructor(test_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
@@ -1138,7 +1173,7 @@
         });
         call.cancel();
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1160,7 +1195,7 @@
         });
         call.cancel();
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1180,7 +1215,7 @@
         });
         call.cancel();
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1204,7 +1239,7 @@
         });
         call.cancel();
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1235,7 +1270,7 @@
           }
         });
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1259,7 +1294,7 @@
           done();
         });
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1279,14 +1314,14 @@
   var server;
   before(function() {
     server = new grpc.Server();
-    server.addProtoService(mathService, {
+    server.addService(mathServiceAttrs, {
       'div': function(stream) {},
       'divMany': function(stream) {},
       'fib': function(stream) {},
       'sum': function(stream) {}
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    var Client = surface_client.makeProtobufClientConstructor(mathService);
+    var Client = surface_client.makeClientConstructor(mathServiceAttrs);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
diff --git a/src/node/test/test_messages.proto b/src/node/test/test_messages.proto
index a1a6a32..ae70f6e 100644
--- a/src/node/test/test_messages.proto
+++ b/src/node/test/test_messages.proto
@@ -41,3 +41,20 @@
   bytes bytes_field = 1;
   repeated int32 repeated_field = 2;
 }
+
+message OneOfValues {
+  oneof oneof_choice {
+    int32 int_choice = 1;
+    string string_choice = 2;
+  }
+}
+
+enum TestEnum {
+  ZERO = 0;
+  ONE = 1;
+  TWO = 2;
+}
+
+message EnumValues {
+  TestEnum enum_value = 1;
+}
\ No newline at end of file
diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh
index bd7c294..0e82bca 100755
--- a/src/objective-c/tests/run_tests.sh
+++ b/src/objective-c/tests/run_tests.sh
@@ -68,12 +68,16 @@
     -destination name="iPhone 6" \
     test | xcpretty
 
-echo "TIME:  $(date)"
-xcodebuild \
-    -workspace Tests.xcworkspace \
-    -scheme CronetUnitTests \
-    -destination name="iPhone 6" \
-    test | xcpretty
+# Temporarily disabled for (possible) flakiness on Jenkins.
+# Fix or reenable after confirmation/disconfirmation that it is the source of
+# Jenkins problem.
+
+# echo "TIME:  $(date)"
+# xcodebuild \
+#     -workspace Tests.xcworkspace \
+#     -scheme CronetUnitTests \
+#     -destination name="iPhone 6" \
+#     test | xcpretty
 
 echo "TIME:  $(date)"
 xcodebuild \
diff --git a/src/proto/grpc/testing/control.proto b/src/proto/grpc/testing/control.proto
index 8f0d25c..acee866 100644
--- a/src/proto/grpc/testing/control.proto
+++ b/src/proto/grpc/testing/control.proto
@@ -113,6 +113,9 @@
   string other_client_api = 15;
 
   repeated ChannelArg channel_args = 16;
+
+  // Number of messages on a stream before it gets finished/restarted
+  int32 messages_per_stream = 18;
 }
 
 message ClientStatus { ClientStats stats = 1; }
diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py
index 47838c2..f29c44a 100644
--- a/src/python/grpcio/grpc/_server.py
+++ b/src/python/grpcio/grpc/_server.py
@@ -705,6 +705,10 @@
                     state.rpc_states.remove(rpc_state)
                     if _stop_serving(state):
                         return
+        # We want to force the deletion of the previous event
+        # ~before~ we poll again; if the event has a reference
+        # to a shutdown Call object, this can induce spinlock.
+        event = None
 
 
 def _stop(state, grace):
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index ed8793b..3bcbe66 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -88,7 +88,6 @@
   'src/core/lib/channel/handshaker_registry.c',
   'src/core/lib/channel/http_client_filter.c',
   'src/core/lib/channel/http_server_filter.c',
-  'src/core/lib/channel/max_age_filter.c',
   'src/core/lib/channel/message_size_filter.c',
   'src/core/lib/compression/compression.c',
   'src/core/lib/compression/message_compress.c',
@@ -253,47 +252,47 @@
   'src/core/tsi/transport_security.c',
   'src/core/ext/transport/chttp2/server/chttp2_server.c',
   'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
-  'src/core/ext/client_channel/channel_connectivity.c',
-  'src/core/ext/client_channel/client_channel.c',
-  'src/core/ext/client_channel/client_channel_factory.c',
-  'src/core/ext/client_channel/client_channel_plugin.c',
-  'src/core/ext/client_channel/connector.c',
-  'src/core/ext/client_channel/http_connect_handshaker.c',
-  'src/core/ext/client_channel/http_proxy.c',
-  'src/core/ext/client_channel/lb_policy.c',
-  'src/core/ext/client_channel/lb_policy_factory.c',
-  'src/core/ext/client_channel/lb_policy_registry.c',
-  'src/core/ext/client_channel/parse_address.c',
-  'src/core/ext/client_channel/proxy_mapper.c',
-  'src/core/ext/client_channel/proxy_mapper_registry.c',
-  'src/core/ext/client_channel/resolver.c',
-  'src/core/ext/client_channel/resolver_factory.c',
-  'src/core/ext/client_channel/resolver_registry.c',
-  'src/core/ext/client_channel/retry_throttle.c',
-  'src/core/ext/client_channel/subchannel.c',
-  'src/core/ext/client_channel/subchannel_index.c',
-  'src/core/ext/client_channel/uri_parser.c',
+  'src/core/ext/filters/client_channel/channel_connectivity.c',
+  'src/core/ext/filters/client_channel/client_channel.c',
+  'src/core/ext/filters/client_channel/client_channel_factory.c',
+  'src/core/ext/filters/client_channel/client_channel_plugin.c',
+  'src/core/ext/filters/client_channel/connector.c',
+  'src/core/ext/filters/client_channel/http_connect_handshaker.c',
+  'src/core/ext/filters/client_channel/http_proxy.c',
+  'src/core/ext/filters/client_channel/lb_policy.c',
+  'src/core/ext/filters/client_channel/lb_policy_factory.c',
+  'src/core/ext/filters/client_channel/lb_policy_registry.c',
+  'src/core/ext/filters/client_channel/parse_address.c',
+  'src/core/ext/filters/client_channel/proxy_mapper.c',
+  'src/core/ext/filters/client_channel/proxy_mapper_registry.c',
+  'src/core/ext/filters/client_channel/resolver.c',
+  'src/core/ext/filters/client_channel/resolver_factory.c',
+  'src/core/ext/filters/client_channel/resolver_registry.c',
+  'src/core/ext/filters/client_channel/retry_throttle.c',
+  'src/core/ext/filters/client_channel/subchannel.c',
+  'src/core/ext/filters/client_channel/subchannel_index.c',
+  'src/core/ext/filters/client_channel/uri_parser.c',
   'src/core/ext/transport/chttp2/client/chttp2_connector.c',
   'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
   'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
   'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
   'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
-  'src/core/ext/lb_policy/grpclb/grpclb.c',
-  'src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c',
-  'src/core/ext/lb_policy/grpclb/load_balancer_api.c',
-  'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
+  'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c',
+  'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c',
+  'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c',
+  'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
   'third_party/nanopb/pb_common.c',
   'third_party/nanopb/pb_decode.c',
   'third_party/nanopb/pb_encode.c',
-  'src/core/ext/lb_policy/pick_first/pick_first.c',
-  'src/core/ext/lb_policy/round_robin/round_robin.c',
-  'src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c',
-  'src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
-  'src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c',
-  'src/core/ext/resolver/dns/native/dns_resolver.c',
-  'src/core/ext/resolver/sockaddr/sockaddr_resolver.c',
-  'src/core/ext/load_reporting/load_reporting.c',
-  'src/core/ext/load_reporting/load_reporting_filter.c',
+  'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c',
+  'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c',
+  'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c',
+  'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
+  'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c',
+  'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c',
+  'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c',
+  'src/core/ext/filters/load_reporting/load_reporting.c',
+  'src/core/ext/filters/load_reporting/load_reporting_filter.c',
   'src/core/ext/census/base_resources.c',
   'src/core/ext/census/context.c',
   'src/core/ext/census/gen/census.pb.c',
@@ -308,6 +307,7 @@
   'src/core/ext/census/resource.c',
   'src/core/ext/census/trace_context.c',
   'src/core/ext/census/tracing.c',
+  'src/core/ext/filters/max_age/max_age_filter.c',
   'src/core/plugin_registry/grpc_plugin_registry.c',
   'src/boringssl/err_data.c',
   'third_party/boringssl/crypto/aes/aes.c',
diff --git a/src/python/grpcio_reflection/MANIFEST.in b/src/python/grpcio_reflection/MANIFEST.in
new file mode 100644
index 0000000..0f2130c
--- /dev/null
+++ b/src/python/grpcio_reflection/MANIFEST.in
@@ -0,0 +1,4 @@
+include grpc_version.py
+include reflection_commands.py
+graft grpc_reflection
+global-exclude *.pyc
diff --git a/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
index c8ad966..c58cb3e 100644
--- a/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
+++ b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
@@ -143,12 +143,13 @@
                         .encode(),))
 
 
-def enable_server_reflection(service_names, server):
+def enable_server_reflection(service_names, server, pool=None):
     """Enables server reflection on a server.
 
     Args:
       service_names: Iterable of fully-qualified service names available.
       server: grpc.Server to which reflection service will be added.
+      pool: DescriptorPool object to use (descriptor_pool.Default() if None).
     """
     reflection_pb2_grpc.add_ServerReflectionServicer_to_server(
-        ReflectionServicer(service_names), server)
+        ReflectionServicer(service_names), server, pool)
diff --git a/src/ruby/end2end/channel_closing_driver.rb b/src/ruby/end2end/channel_closing_driver.rb
index 43e2fe8..d3e5373 100755
--- a/src/ruby/end2end/channel_closing_driver.rb
+++ b/src/ruby/end2end/channel_closing_driver.rb
@@ -36,7 +36,7 @@
 
 def main
   STDERR.puts 'start server'
-  server_runner = ServerRunner.new
+  server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
 
   sleep 1
diff --git a/src/ruby/end2end/channel_state_driver.rb b/src/ruby/end2end/channel_state_driver.rb
index c3184bf..80fb628 100755
--- a/src/ruby/end2end/channel_state_driver.rb
+++ b/src/ruby/end2end/channel_state_driver.rb
@@ -35,7 +35,7 @@
 
 def main
   STDERR.puts 'start server'
-  server_runner = ServerRunner.new
+  server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
 
   sleep 1
diff --git a/src/ruby/end2end/end2end_common.rb b/src/ruby/end2end/end2end_common.rb
index 9534bb2..1c87ced 100755
--- a/src/ruby/end2end/end2end_common.rb
+++ b/src/ruby/end2end/end2end_common.rb
@@ -55,13 +55,14 @@
 
 # ServerRunner starts an "echo server" that test clients can make calls to
 class ServerRunner
-  def initialize
+  def initialize(service_impl)
+    @service_impl = service_impl
   end
 
   def run
     @srv = GRPC::RpcServer.new
     port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
-    @srv.handle(EchoServerImpl)
+    @srv.handle(@service_impl)
 
     @thd = Thread.new do
       @srv.run
diff --git a/tools/profiling/latency_profile/run_latency_profile.sh b/src/ruby/end2end/killed_client_thread_client.rb
similarity index 64%
copy from tools/profiling/latency_profile/run_latency_profile.sh
copy to src/ruby/end2end/killed_client_thread_client.rb
index 41423fc..d5a7db7 100755
--- a/tools/profiling/latency_profile/run_latency_profile.sh
+++ b/src/ruby/end2end/killed_client_thread_client.rb
@@ -1,5 +1,6 @@
-#!/bin/bash
-# Copyright 2016, Google Inc.
+#!/usr/bin/env ruby
+
+# Copyright 2015, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -28,25 +29,30 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set -ex
+# Attempt to reproduce
+# https://github.com/GoogleCloudPlatform/google-cloud-ruby/issues/1327
 
-cd $(dirname $0)/../../..
+require_relative './end2end_common'
 
-CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
+def main
+  server_port = ''
+  OptionParser.new do |opts|
+    opts.on('--client_control_port=P', String) do
+      STDERR.puts 'client control port not used'
+    end
+    opts.on('--server_port=P', String) do |p|
+      server_port = p
+    end
+  end.parse!
 
-# try to use pypy for generating reports
-# each trace dumps 7-8gig of text to disk, and processing this into a report is
-# heavyweight - so any speed boost is worthwhile
-# TODO(ctiller): consider rewriting report generation in C++ for performance
-if which pypy >/dev/null; then
-  PYTHON=pypy
-else
-  PYTHON=python2.7
-fi
+  thd = Thread.new do
+    stub = Echo::EchoServer::Stub.new("localhost:#{server_port}",
+                                      :this_channel_is_insecure)
+    stub.echo(Echo::EchoRequest.new(request: 'hello'))
+    fail 'the clients rpc in this test shouldnt complete. ' \
+      'expecting SIGINT to happen in the middle of the call'
+  end
+  thd.join
+end
 
-make CONFIG=opt memory_profile_test memory_profile_client memory_profile_server
-bins/opt/memory_profile_test
-bq load microbenchmarks.memory memory_usage.csv
-
-$PYTHON tools/run_tests/run_microbenchmark.py --collect summary perf latency --bigquery_upload
-
+main
diff --git a/src/ruby/end2end/killed_client_thread_driver.rb b/src/ruby/end2end/killed_client_thread_driver.rb
new file mode 100755
index 0000000..f76d3e1
--- /dev/null
+++ b/src/ruby/end2end/killed_client_thread_driver.rb
@@ -0,0 +1,114 @@
+#!/usr/bin/env ruby
+
+# 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.
+
+require_relative './end2end_common'
+
+# Service that sleeps for a long time upon receiving an 'echo request'
+# Also, this notifies @call_started_cv once it has received a request.
+class SleepingEchoServerImpl < Echo::EchoServer::Service
+  def initialize(call_started, call_started_mu, call_started_cv)
+    @call_started = call_started
+    @call_started_mu = call_started_mu
+    @call_started_cv = call_started_cv
+  end
+
+  def echo(echo_req, _)
+    @call_started_mu.synchronize do
+      @call_started.set_true
+      @call_started_cv.signal
+    end
+    sleep 1000
+    Echo::EchoReply.new(response: echo_req.request)
+  end
+end
+
+# Mutable boolean
+class BoolHolder
+  attr_reader :val
+
+  def init
+    @val = false
+  end
+
+  def set_true
+    @val = true
+  end
+end
+
+def main
+  STDERR.puts 'start server'
+
+  call_started = BoolHolder.new
+  call_started_mu = Mutex.new
+  call_started_cv = ConditionVariable.new
+
+  service_impl = SleepingEchoServerImpl.new(call_started,
+                                            call_started_mu,
+                                            call_started_cv)
+  server_runner = ServerRunner.new(service_impl)
+  server_port = server_runner.run
+
+  STDERR.puts 'start client'
+  _, client_pid = start_client('killed_client_thread_client.rb',
+                               server_port)
+
+  call_started_mu.synchronize do
+    call_started_cv.wait(call_started_mu) until call_started.val
+  end
+
+  # SIGINT the child process now that it's
+  # in the middle of an RPC (happening on a non-main thread)
+  Process.kill('SIGINT', client_pid)
+  STDERR.puts 'sent shutdown'
+
+  begin
+    Timeout.timeout(10) do
+      Process.wait(client_pid)
+    end
+  rescue Timeout::Error
+    STDERR.puts "timeout wait for client pid #{client_pid}"
+    Process.kill('SIGKILL', client_pid)
+    Process.wait(client_pid)
+    STDERR.puts 'killed client child'
+    raise 'Timed out waiting for client process. ' \
+      'It likely hangs when killed while in the middle of an rpc'
+  end
+
+  client_exit_code = $CHILD_STATUS
+  if client_exit_code.termsig != 2 # SIGINT
+    fail 'expected client exit from SIGINT ' \
+      "but got child status: #{client_exit_code}"
+  end
+
+  server_runner.stop
+end
+
+main
diff --git a/src/ruby/end2end/sig_handling_driver.rb b/src/ruby/end2end/sig_handling_driver.rb
index c5d46e0..6691464 100755
--- a/src/ruby/end2end/sig_handling_driver.rb
+++ b/src/ruby/end2end/sig_handling_driver.rb
@@ -36,7 +36,7 @@
 
 def main
   STDERR.puts 'start server'
-  server_runner = ServerRunner.new
+  server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
 
   sleep 1
diff --git a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
index 84d039b..670cda0 100755
--- a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
+++ b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
@@ -36,7 +36,7 @@
 
 def main
   STDERR.puts 'start server'
-  server_runner = ServerRunner.new
+  server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
 
   sleep 1
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 82d340b..344cb94 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -784,7 +784,7 @@
    Only one operation of each type can be active at once in any given
    batch */
 static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
-  run_batch_stack st;
+  run_batch_stack *st = NULL;
   grpc_rb_call *call = NULL;
   grpc_event ev;
   grpc_call_error err;
@@ -792,6 +792,7 @@
   VALUE rb_write_flag = rb_ivar_get(self, id_write_flag);
   unsigned write_flag = 0;
   void *tag = (void*)&st;
+
   if (RTYPEDDATA_DATA(self) == NULL) {
     rb_raise(grpc_rb_eCallError, "Cannot run batch on closed call");
     return Qnil;
@@ -806,14 +807,16 @@
   if (rb_write_flag != Qnil) {
     write_flag = NUM2UINT(rb_write_flag);
   }
-  grpc_run_batch_stack_init(&st, write_flag);
-  grpc_run_batch_stack_fill_ops(&st, ops_hash);
+  st = gpr_malloc(sizeof(run_batch_stack));
+  grpc_run_batch_stack_init(st, write_flag);
+  grpc_run_batch_stack_fill_ops(st, ops_hash);
 
   /* call grpc_call_start_batch, then wait for it to complete using
    * pluck_event */
-  err = grpc_call_start_batch(call->wrapped, st.ops, st.op_num, tag, NULL);
+  err = grpc_call_start_batch(call->wrapped, st->ops, st->op_num, tag, NULL);
   if (err != GRPC_CALL_OK) {
-    grpc_run_batch_stack_cleanup(&st);
+    grpc_run_batch_stack_cleanup(st);
+    gpr_free(st);
     rb_raise(grpc_rb_eCallError,
              "grpc_call_start_batch failed with %s (code=%d)",
              grpc_call_error_detail_of(err), err);
@@ -826,8 +829,9 @@
   }
   /* Build and return the BatchResult struct result,
      if there is an error, it's reflected in the status */
-  result = grpc_run_batch_stack_build_result(&st);
-  grpc_run_batch_stack_cleanup(&st);
+  result = grpc_run_batch_stack_build_result(st);
+  grpc_run_batch_stack_cleanup(st);
+  gpr_free(st);
   return result;
 }
 
diff --git a/templates/binding.gyp.template b/templates/binding.gyp.template
index 5ac97d2..aeeb56b 100644
--- a/templates/binding.gyp.template
+++ b/templates/binding.gyp.template
@@ -47,9 +47,37 @@
       # Some Node installations use the system installation of OpenSSL, and on
       # some systems, the system OpenSSL still does not have ALPN support. This
       # will let users recompile gRPC to work without ALPN.
-      'grpc_alpn%': 'true'
+      'grpc_alpn%': 'true',
+      # Indicates that the library should be built with gcov.
+      'grpc_gcov%': 'false'
     },
     'target_defaults': {
+      'configurations': {
+        % for name, args in configs.iteritems():
+        %  if name in ['dbg', 'opt']:
+        '${{'dbg':'Debug', 'opt': 'Release'}[name]}': {
+          % for arg, prop in [('CPPFLAGS', 'cflags'), ('DEFINES', 'defines')]:
+          %  if args.get(arg, None) is not None:
+          '${prop}': [
+            % for item in args.get(arg).split():
+              '${item}',
+            % endfor
+          ],
+          %  endif
+          % endfor
+        },
+        %  endif
+        % endfor
+      },
+      % for arg, prop in [('CPPFLAGS', 'cflags'), ('LDFLAGS', 'ldflags')]:
+      %  if defaults['global'].get(arg, None) is not None:
+      '${prop}': [
+        % for item in defaults['global'].get(arg).split():
+          '${item}',
+        % endfor
+      ],
+      %  endif
+      % endfor
       'include_dirs': [
         '.',
         'include'
@@ -66,6 +94,17 @@
             'GRPC_UV'
           ]
         }],
+        ['grpc_gcov=="true"', {
+          % for arg, prop in [('CPPFLAGS', 'cflags'), ('DEFINES', 'defines'), ('LDFLAGS', 'ldflags')]:
+          %  if configs['gcov'].get(arg, None) is not None:
+          '${prop}': [
+            % for item in configs['gcov'].get(arg).split():
+              '${item}',
+            % endfor
+          ],
+          %  endif
+          % endfor
+        }],
         ['OS!="win" and runtime=="electron"', {
           "defines": [
             'OPENSSL_NO_THREADS'
@@ -128,26 +167,9 @@
             "ws2_32"
           ]
         }, { # OS != "win"
-          'variables': {
-            'config': '<!(echo $CONFIG)',
-          },
           'include_dirs': [
             '<(node_root_dir)/deps/zlib',
-            '<(node_root_dir)/deps/cares/include',
-          ],
-          'conditions': [
-            ['config=="gcov"', {
-              'cflags': [
-                '-ftest-coverage',
-                '-fprofile-arcs',
-                '-O0'
-              ],
-              'ldflags': [
-                '-ftest-coverage',
-                '-fprofile-arcs'
-              ]
-            }
-           ]
+            '<(node_root_dir)/deps/cares/include'
           ]
         }]
       ]
@@ -284,16 +306,10 @@
         ],
         'cflags': [
           '-std=c++11',
-          '-Wall',
           '-pthread',
-          '-g',
           '-zdefs',
-          '-Werror',
           '-Wno-error=deprecated-declarations'
         ],
-        'ldflags': [
-          '-g'
-        ],
         "conditions": [
           ['OS=="win" or runtime=="electron"', {
             'dependencies': [
diff --git a/templates/grpc.gemspec.template b/templates/grpc.gemspec.template
index 462ea52..80ce643 100644
--- a/templates/grpc.gemspec.template
+++ b/templates/grpc.gemspec.template
@@ -26,7 +26,7 @@
     s.files += Dir.glob('include/grpc/**/*')
     s.test_files = Dir.glob('src/ruby/spec/**/*')
     s.bindir = 'src/ruby/bin'
-    s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
+    s.require_paths = %w( src/ruby/lib src/ruby/bin src/ruby/pb )
     s.platform      = Gem::Platform::RUBY
 
     s.add_dependency 'google-protobuf', '~> 3.1'
diff --git a/templates/package.json.template b/templates/package.json.template
index d093883..b69fd28 100644
--- a/templates/package.json.template
+++ b/templates/package.json.template
@@ -36,7 +36,7 @@
       "lodash": "^4.15.0",
       "nan": "^2.0.0",
       "node-pre-gyp": "^0.6.0",
-      "protobufjs": "^5.0.0",
+      "protobufjs": "^6.7.0",
       "cares": "^1.1.5"
     },
     "devDependencies": {
diff --git a/templates/tools/dockerfile/csharp_dotnetcli_deps.include b/templates/tools/dockerfile/csharp_dotnetcli_deps.include
index 058ce15..bc88d2b 100644
--- a/templates/tools/dockerfile/csharp_dotnetcli_deps.include
+++ b/templates/tools/dockerfile/csharp_dotnetcli_deps.include
@@ -1,7 +1,7 @@
 # Install dotnet SDK based on https://www.microsoft.com/net/core#debian
 RUN apt-get update && apt-get install -y curl libunwind8 gettext
-# dotnet-dev-1.0.0-preview2-003121
-RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=809130
+# dotnet-dev-1.0.0-preview2-003131
+RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
 RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
 # dotnet-dev-1.0.1
 RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index 4870dc1..9a566e6 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -117,10 +117,7 @@
   grpc_init();
 
   /* Create endpoints */
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("bad_client_test");
-  sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  sfd = grpc_iomgr_create_endpoint_pair("fixture", NULL);
 
   /* Create server, completion events */
   a.server = grpc_server_create(NULL, NULL);
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index af551c4..4be89c7 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -73,7 +73,7 @@
 }
 
 static void call_func(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                      grpc_transport_stream_op *op) {
+                      grpc_transport_stream_op_batch *op) {
   ++*(int *)(elem->call_data);
 }
 
diff --git a/test/core/client_channel/lb_policies_test.c b/test/core/client_channel/lb_policies_test.c
index 057b90e..e03492f 100644
--- a/test/core/client_channel/lb_policies_test.c
+++ b/test/core/client_channel/lb_policies_test.c
@@ -41,8 +41,8 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 
-#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/client_channel/lb_policy_registry.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/support/string.h"
diff --git a/test/core/client_channel/parse_address_test.c b/test/core/client_channel/parse_address_test.c
index 37dd0fb..629cdb0 100644
--- a/test/core/client_channel/parse_address_test.c
+++ b/test/core/client_channel/parse_address_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/parse_address.h"
+#include "src/core/ext/filters/client_channel/parse_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 
 #include <string.h>
diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
index 8449afc..8e15faa 100644
--- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
+++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
@@ -36,8 +36,8 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 
-#include "src/core/ext/client_channel/resolver.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/resolver.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/resolve_address.h"
diff --git a/test/core/client_channel/resolvers/dns_resolver_test.c b/test/core/client_channel/resolvers/dns_resolver_test.c
index 919a85d..fa7857d 100644
--- a/test/core/client_channel/resolvers/dns_resolver_test.c
+++ b/test/core/client_channel/resolvers/dns_resolver_test.c
@@ -35,7 +35,7 @@
 
 #include <grpc/support/log.h>
 
-#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/client_channel/resolvers/sockaddr_resolver_test.c b/test/core/client_channel/resolvers/sockaddr_resolver_test.c
index bc4f02c..847eaba 100644
--- a/test/core/client_channel/resolvers/sockaddr_resolver_test.c
+++ b/test/core/client_channel/resolvers/sockaddr_resolver_test.c
@@ -37,7 +37,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/combiner.h"
 
diff --git a/test/core/client_channel/uri_fuzzer_test.c b/test/core/client_channel/uri_fuzzer_test.c
index baadd4f..51da7f9 100644
--- a/test/core/client_channel/uri_fuzzer_test.c
+++ b/test/core/client_channel/uri_fuzzer_test.c
@@ -37,7 +37,7 @@
 
 #include <grpc/support/alloc.h>
 
-#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
 bool squelch = true;
diff --git a/test/core/client_channel/uri_parser_test.c b/test/core/client_channel/uri_parser_test.c
index 8a127f7..9fd0dd0 100644
--- a/test/core/client_channel/uri_parser_test.c
+++ b/test/core/client_channel/uri_parser_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/ext/filters/client_channel/uri_parser.h"
 
 #include <string.h>
 
diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c
index 64bdceb..1187e59 100644
--- a/test/core/end2end/end2end_nosec_tests.c
+++ b/test/core/end2end/end2end_nosec_tests.c
@@ -49,6 +49,8 @@
 extern void authority_not_supported_pre_init(void);
 extern void bad_hostname(grpc_end2end_test_config config);
 extern void bad_hostname_pre_init(void);
+extern void bad_ping(grpc_end2end_test_config config);
+extern void bad_ping_pre_init(void);
 extern void binary_metadata(grpc_end2end_test_config config);
 extern void binary_metadata_pre_init(void);
 extern void cancel_after_accept(grpc_end2end_test_config config);
@@ -154,6 +156,7 @@
   grpc_summon_debugger_macros();
   authority_not_supported_pre_init();
   bad_hostname_pre_init();
+  bad_ping_pre_init();
   binary_metadata_pre_init();
   cancel_after_accept_pre_init();
   cancel_after_client_done_pre_init();
@@ -214,6 +217,7 @@
   if (argc <= 1) {
     authority_not_supported(config);
     bad_hostname(config);
+    bad_ping(config);
     binary_metadata(config);
     cancel_after_accept(config);
     cancel_after_client_done(config);
@@ -275,6 +279,10 @@
       bad_hostname(config);
       continue;
     }
+    if (0 == strcmp("bad_ping", argv[i])) {
+      bad_ping(config);
+      continue;
+    }
     if (0 == strcmp("binary_metadata", argv[i])) {
       binary_metadata(config);
       continue;
diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c
index 37c1be4..966031a 100644
--- a/test/core/end2end/end2end_tests.c
+++ b/test/core/end2end/end2end_tests.c
@@ -49,6 +49,8 @@
 extern void authority_not_supported_pre_init(void);
 extern void bad_hostname(grpc_end2end_test_config config);
 extern void bad_hostname_pre_init(void);
+extern void bad_ping(grpc_end2end_test_config config);
+extern void bad_ping_pre_init(void);
 extern void binary_metadata(grpc_end2end_test_config config);
 extern void binary_metadata_pre_init(void);
 extern void call_creds(grpc_end2end_test_config config);
@@ -156,6 +158,7 @@
   grpc_summon_debugger_macros();
   authority_not_supported_pre_init();
   bad_hostname_pre_init();
+  bad_ping_pre_init();
   binary_metadata_pre_init();
   call_creds_pre_init();
   cancel_after_accept_pre_init();
@@ -217,6 +220,7 @@
   if (argc <= 1) {
     authority_not_supported(config);
     bad_hostname(config);
+    bad_ping(config);
     binary_metadata(config);
     call_creds(config);
     cancel_after_accept(config);
@@ -279,6 +283,10 @@
       bad_hostname(config);
       continue;
     }
+    if (0 == strcmp("bad_ping", argv[i])) {
+      bad_ping(config);
+      continue;
+    }
     if (0 == strcmp("binary_metadata", argv[i])) {
       binary_metadata(config);
       continue;
diff --git a/test/core/end2end/fake_resolver.c b/test/core/end2end/fake_resolver.c
index 8a37531..1c7dd13 100644
--- a/test/core/end2end/fake_resolver.c
+++ b/test/core/end2end/fake_resolver.c
@@ -42,9 +42,9 @@
 #include <grpc/support/port_platform.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/ext/client_channel/lb_policy_factory.h"
-#include "src/core/ext/client_channel/parse_address.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/parse_address.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
diff --git a/test/core/end2end/fixtures/h2_census.c b/test/core/end2end/fixtures/h2_census.c
index 8e60123..97b27b2 100644
--- a/test/core/end2end/fixtures/h2_census.c
+++ b/test/core/end2end/fixtures/h2_census.c
@@ -41,7 +41,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
diff --git a/test/core/end2end/fixtures/h2_compress.c b/test/core/end2end/fixtures/h2_compress.c
index c01e456..8aec94d 100644
--- a/test/core/end2end/fixtures/h2_compress.c
+++ b/test/core/end2end/fixtures/h2_compress.c
@@ -41,7 +41,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
diff --git a/test/core/end2end/fixtures/h2_full+pipe.c b/test/core/end2end/fixtures/h2_full+pipe.c
index c6013f3..0191e59 100644
--- a/test/core/end2end/fixtures/h2_full+pipe.c
+++ b/test/core/end2end/fixtures/h2_full+pipe.c
@@ -46,7 +46,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/channel/http_server_filter.h"
diff --git a/test/core/end2end/fixtures/h2_full+trace.c b/test/core/end2end/fixtures/h2_full+trace.c
index 0131637..9dbb27f 100644
--- a/test/core/end2end/fixtures/h2_full+trace.c
+++ b/test/core/end2end/fixtures/h2_full+trace.c
@@ -46,7 +46,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/channel/http_server_filter.h"
diff --git a/test/core/end2end/fixtures/h2_full.c b/test/core/end2end/fixtures/h2_full.c
index 3399f19..49c62b3 100644
--- a/test/core/end2end/fixtures/h2_full.c
+++ b/test/core/end2end/fixtures/h2_full.c
@@ -41,7 +41,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/channel/http_server_filter.h"
diff --git a/test/core/end2end/fixtures/h2_http_proxy.c b/test/core/end2end/fixtures/h2_http_proxy.c
index 55c65fa..62c4355 100644
--- a/test/core/end2end/fixtures/h2_http_proxy.c
+++ b/test/core/end2end/fixtures/h2_http_proxy.c
@@ -42,7 +42,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/channel/http_server_filter.h"
diff --git a/test/core/end2end/fixtures/h2_load_reporting.c b/test/core/end2end/fixtures/h2_load_reporting.c
index 38321f3..79f26ed 100644
--- a/test/core/end2end/fixtures/h2_load_reporting.c
+++ b/test/core/end2end/fixtures/h2_load_reporting.c
@@ -41,8 +41,8 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/load_reporting/load_reporting.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/load_reporting/load_reporting.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
diff --git a/test/core/end2end/fixtures/h2_proxy.c b/test/core/end2end/fixtures/h2_proxy.c
index 9e37ed4..a10738f 100644
--- a/test/core/end2end/fixtures/h2_proxy.c
+++ b/test/core/end2end/fixtures/h2_proxy.c
@@ -41,7 +41,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/channel/http_server_filter.h"
diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.c b/test/core/end2end/fixtures/h2_sockpair+trace.c
index edf42a4..424241c 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.c
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.c
@@ -45,7 +45,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/compress_filter.h"
 #include "src/core/lib/channel/connected_channel.h"
@@ -96,9 +96,7 @@
   f.fixture_data = sfd;
   f.cq = grpc_completion_queue_create(NULL);
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
-  *sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
-  grpc_resource_quota_unref(resource_quota);
+  *sfd = grpc_iomgr_create_endpoint_pair("fixture", NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_sockpair.c b/test/core/end2end/fixtures/h2_sockpair.c
index 94b2623..fe8d766 100644
--- a/test/core/end2end/fixtures/h2_sockpair.c
+++ b/test/core/end2end/fixtures/h2_sockpair.c
@@ -40,7 +40,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/compress_filter.h"
 #include "src/core/lib/channel/connected_channel.h"
@@ -90,9 +90,7 @@
   f.fixture_data = sfd;
   f.cq = grpc_completion_queue_create(NULL);
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
-  *sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
-  grpc_resource_quota_unref(resource_quota);
+  *sfd = grpc_iomgr_create_endpoint_pair("fixture", NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.c b/test/core/end2end/fixtures/h2_sockpair_1byte.c
index 6f9cf8f..04174fa 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.c
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.c
@@ -40,7 +40,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/compress_filter.h"
 #include "src/core/lib/channel/connected_channel.h"
@@ -90,9 +90,17 @@
   f.fixture_data = sfd;
   f.cq = grpc_completion_queue_create(NULL);
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
-  *sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 1);
-  grpc_resource_quota_unref(resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = 1},
+                  {.key = GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = 1},
+                  {.key = GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = 1}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  *sfd = grpc_iomgr_create_endpoint_pair("fixture", &args);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_uds.c b/test/core/end2end/fixtures/h2_uds.c
index bc973ea..7bde69d 100644
--- a/test/core/end2end/fixtures/h2_uds.c
+++ b/test/core/end2end/fixtures/h2_uds.c
@@ -44,7 +44,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/channel/http_server_filter.h"
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5242554383597568 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5242554383597568
new file mode 100644
index 0000000..95a0b01
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5242554383597568
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6499902139924480 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6499902139924480
new file mode 100644
index 0000000..139fc1c
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6499902139924480
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6699208922890240 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6699208922890240
new file mode 100644
index 0000000..74f189b
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6699208922890240
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-6312731374256128 b/test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-6312731374256128
new file mode 100644
index 0000000..4c6eb60
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-6312731374256128
Binary files differ
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index 3c5068f..d1e510d 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -93,6 +93,7 @@
 END2END_TESTS = {
     'authority_not_supported': default_test_options,
     'bad_hostname': default_test_options,
+    'bad_ping': connectivity_test_options._replace(proxyable=False),
     'binary_metadata': default_test_options,
     'resource_quota_server': default_test_options._replace(large_writes=True,
                                                            proxyable=False),
diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl
index 1041219..dc0925d 100755
--- a/test/core/end2end/generate_tests.bzl
+++ b/test/core/end2end/generate_tests.bzl
@@ -85,6 +85,7 @@
 # maps test names to options
 END2END_TESTS = {
     'bad_hostname': test_options(),
+    'bad_ping': test_options(),
     'binary_metadata': test_options(),
     'resource_quota_server': test_options(proxyable=False),
     'call_creds': test_options(secure=True),
diff --git a/test/core/end2end/tests/authority_not_supported.c b/test/core/end2end/tests/authority_not_supported.c
index 7db2fd6..192a20d 100644
--- a/test/core/end2end/tests/authority_not_supported.c
+++ b/test/core/end2end/tests/authority_not_supported.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -102,7 +104,6 @@
       grpc_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_metadata meta_c[2] = {{grpc_slice_from_static_string("key1"),
                               grpc_slice_from_static_string("val1"),
                               0,
@@ -124,6 +125,7 @@
   grpc_slice details;
 
   grpc_slice host = grpc_slice_from_static_string("foo.test.google.fr");
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
                                grpc_slice_from_static_string("/foo"), &host,
                                deadline, NULL);
diff --git a/test/core/end2end/tests/bad_hostname.c b/test/core/end2end/tests/bad_hostname.c
index f50a580..c63c9c7 100644
--- a/test/core/end2end/tests/bad_hostname.c
+++ b/test/core/end2end/tests/bad_hostname.c
@@ -59,16 +59,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -99,7 +101,6 @@
 
 static void simple_request_body(grpc_end2end_test_fixture f) {
   grpc_call *c;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -112,6 +113,7 @@
   grpc_slice details;
 
   grpc_slice host = grpc_slice_from_static_string("slartibartfast.local");
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
                                grpc_slice_from_static_string("/foo"), &host,
                                deadline, NULL);
diff --git a/test/core/end2end/tests/bad_ping.c b/test/core/end2end/tests/bad_ping.c
new file mode 100644
index 0000000..01a6aea
--- /dev/null
+++ b/test/core/end2end/tests/bad_ping.c
@@ -0,0 +1,237 @@
+/*
+ *
+ * Copyright 2017, 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/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+
+#include "test/core/end2end/cq_verifier.h"
+
+#define MAX_PING_STRIKES 1
+
+static void *tag(intptr_t t) { return (void *)t; }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, grpc_timeout_seconds_to_deadline(5),
+                                    NULL);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+}
+
+static void test_bad_ping(grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f = config.create_fixture(NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
+  grpc_arg client_a[] = {{.type = GRPC_ARG_INTEGER,
+                          .key = GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS,
+                          .value.integer = 0},
+                         {.type = GRPC_ARG_INTEGER,
+                          .key = GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA,
+                          .value.integer = 20},
+                         {.type = GRPC_ARG_INTEGER,
+                          .key = GRPC_ARG_HTTP2_BDP_PROBE,
+                          .value.integer = 0}};
+  grpc_arg server_a[] = {
+      {.type = GRPC_ARG_INTEGER,
+       .key = GRPC_ARG_HTTP2_MIN_PING_INTERVAL_WITHOUT_DATA_MS,
+       .value.integer = 300000 /* 5 minutes */},
+      {.type = GRPC_ARG_INTEGER,
+       .key = GRPC_ARG_HTTP2_MAX_PING_STRIKES,
+       .value.integer = MAX_PING_STRIKES}};
+  grpc_channel_args client_args = {.num_args = GPR_ARRAY_SIZE(client_a),
+                                   .args = client_a};
+  grpc_channel_args server_args = {.num_args = GPR_ARRAY_SIZE(server_a),
+                                   .args = server_a};
+
+  config.init_client(&f, &client_args);
+  config.init_server(&f, &server_args);
+
+  grpc_call *c;
+  grpc_call *s;
+  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/foo"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      NULL);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->data.send_initial_metadata.metadata = NULL;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  cq_verify(cqv);
+
+  // Send too many pings to the server to trigger the punishment:
+  // The first ping is sent after data frames, it won't trigger a ping strike.
+  // Each of the following pings will trigger a ping strike, and we need at
+  // least (MAX_PING_STRIKES + 1) strikes to trigger the punishment. So
+  // (MAX_PING_STRIKES + 2) pings are needed here.
+  int i;
+  for (i = 200; i < 202 + MAX_PING_STRIKES; i++) {
+    grpc_channel_ping(f.client, f.cq, tag(i), NULL);
+    CQ_EXPECT_COMPLETION(cqv, tag(i), 1);
+    cq_verify(cqv);
+  }
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+  op->data.send_status_from_server.status_details = &status_details;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
+  CQ_EXPECT_COMPLETION(cqv, tag(0xdead), 1);
+  cq_verify(cqv);
+
+  grpc_call_destroy(s);
+
+  // The connection should be closed immediately after the misbehaved pings,
+  // the in-progress RPC should fail.
+  GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "Endpoint read failed"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_call_destroy(c);
+  cq_verifier_destroy(cqv);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void bad_ping(grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION);
+  test_bad_ping(config);
+}
+
+void bad_ping_pre_init(void) {}
diff --git a/test/core/end2end/tests/binary_metadata.c b/test/core/end2end/tests/binary_metadata.c
index 7fb60f4..9cb17c9 100644
--- a/test/core/end2end/tests/binary_metadata.c
+++ b/test/core/end2end/tests/binary_metadata.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -108,7 +110,6 @@
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_metadata meta_c[2] = {
       {grpc_slice_from_static_string("key1-bin"),
        grpc_slice_from_static_string(
@@ -147,6 +148,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/call_creds.c b/test/core/end2end/tests/call_creds.c
index 38cba50..d65073f 100644
--- a/test/core/end2end/tests/call_creds.c
+++ b/test/core/end2end/tests/call_creds.c
@@ -75,16 +75,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -143,7 +145,6 @@
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_end2end_test_fixture f;
   cq_verifier *cqv;
   grpc_op ops[6];
@@ -165,6 +166,7 @@
   f = begin_test(config, test_name, 0);
   cqv = cq_verifier_create(f.cq);
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
@@ -383,7 +385,7 @@
   grpc_op *op;
   grpc_call *c;
   grpc_end2end_test_fixture f;
-  gpr_timespec deadline = five_seconds_time();
+  gpr_timespec deadline = five_seconds_from_now();
   cq_verifier *cqv;
   grpc_metadata_array initial_metadata_recv;
   grpc_metadata_array trailing_metadata_recv;
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
index 1a92aa4..bda061c 100644
--- a/test/core/end2end/tests/cancel_after_accept.c
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -64,16 +64,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -110,9 +112,6 @@
   grpc_op *op;
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = use_service_config
-                              ? gpr_inf_future(GPR_CLOCK_MONOTONIC)
-                              : five_seconds_time();
   grpc_metadata_array initial_metadata_recv;
   grpc_metadata_array trailing_metadata_recv;
   grpc_metadata_array request_metadata_recv;
@@ -153,6 +152,9 @@
       begin_test(config, "cancel_after_accept", args, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
 
+  gpr_timespec deadline = use_service_config
+                              ? gpr_inf_future(GPR_CLOCK_MONOTONIC)
+                              : five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/service/method"),
diff --git a/test/core/end2end/tests/cancel_after_client_done.c b/test/core/end2end/tests/cancel_after_client_done.c
index 0afeecb..0e72911 100644
--- a/test/core/end2end/tests/cancel_after_client_done.c
+++ b/test/core/end2end/tests/cancel_after_client_done.c
@@ -58,16 +58,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -105,7 +107,6 @@
   grpc_call *s;
   grpc_end2end_test_fixture f = begin_test(
       config, "test_cancel_after_accept_and_writes_closed", NULL, NULL);
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_metadata_array initial_metadata_recv;
   grpc_metadata_array trailing_metadata_recv;
@@ -126,6 +127,7 @@
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/cancel_after_invoke.c b/test/core/end2end/tests/cancel_after_invoke.c
index 8a96ef2..0ee5980 100644
--- a/test/core/end2end/tests/cancel_after_invoke.c
+++ b/test/core/end2end/tests/cancel_after_invoke.c
@@ -60,16 +60,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -106,7 +108,6 @@
   grpc_call *c;
   grpc_end2end_test_fixture f =
       begin_test(config, "test_cancel_after_invoke", mode, NULL, NULL);
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_metadata_array initial_metadata_recv;
   grpc_metadata_array trailing_metadata_recv;
@@ -121,6 +122,7 @@
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/cancel_before_invoke.c b/test/core/end2end/tests/cancel_before_invoke.c
index 586aa7e..7d53091 100644
--- a/test/core/end2end/tests/cancel_before_invoke.c
+++ b/test/core/end2end/tests/cancel_before_invoke.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -103,7 +105,6 @@
   grpc_call *c;
   grpc_end2end_test_fixture f =
       begin_test(config, "cancel_before_invoke", NULL, NULL);
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_metadata_array initial_metadata_recv;
   grpc_metadata_array trailing_metadata_recv;
@@ -118,6 +119,7 @@
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/cancel_in_a_vacuum.c b/test/core/end2end/tests/cancel_in_a_vacuum.c
index bc462dd..c13fc88 100644
--- a/test/core/end2end/tests/cancel_in_a_vacuum.c
+++ b/test/core/end2end/tests/cancel_in_a_vacuum.c
@@ -58,16 +58,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -102,9 +104,9 @@
   grpc_call *c;
   grpc_end2end_test_fixture f =
       begin_test(config, "test_cancel_in_a_vacuum", NULL, NULL);
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *v_client = cq_verifier_create(f.cq);
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/cancel_with_status.c b/test/core/end2end/tests/cancel_with_status.c
index 7d03fe5..1e0e33b 100644
--- a/test/core/end2end/tests/cancel_with_status.c
+++ b/test/core/end2end/tests/cancel_with_status.c
@@ -59,16 +59,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -100,7 +102,6 @@
 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);
   grpc_op ops[6];
   grpc_op *op;
@@ -112,6 +113,7 @@
 
   gpr_log(GPR_DEBUG, "test with %" PRIuPTR " ops", num_ops);
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/compressed_payload.c b/test/core/end2end/tests/compressed_payload.c
index 7dd8c11..c5b750a 100644
--- a/test/core/end2end/tests/compressed_payload.c
+++ b/test/core/end2end/tests/compressed_payload.c
@@ -65,16 +65,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -113,7 +115,6 @@
   grpc_call *s;
   grpc_slice request_payload_slice;
   grpc_byte_buffer *request_payload;
-  gpr_timespec deadline = five_seconds_time();
   grpc_channel_args *client_args;
   grpc_channel_args *server_args;
   grpc_end2end_test_fixture f;
@@ -150,6 +151,7 @@
   f = begin_test(config, test_name, client_args, server_args);
   cqv = cq_verifier_create(f.cq);
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
@@ -290,7 +292,6 @@
   grpc_call *s;
   grpc_slice request_payload_slice;
   grpc_byte_buffer *request_payload;
-  gpr_timespec deadline = five_seconds_time();
   grpc_channel_args *client_args;
   grpc_channel_args *server_args;
   grpc_end2end_test_fixture f;
@@ -329,6 +330,7 @@
   f = begin_test(config, test_name, client_args, server_args);
   cqv = cq_verifier_create(f.cq);
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/default_host.c b/test/core/end2end/tests/default_host.c
index bc1829b..8dccca2 100644
--- a/test/core/end2end/tests/default_host.c
+++ b/test/core/end2end/tests/default_host.c
@@ -59,16 +59,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -100,7 +102,6 @@
 static void simple_request_body(grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -114,6 +115,7 @@
   int was_cancelled = 2;
   char *peer;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
                                grpc_slice_from_static_string("/foo"), NULL,
                                deadline, NULL);
diff --git a/test/core/end2end/tests/disappearing_server.c b/test/core/end2end/tests/disappearing_server.c
index 05440a6..e2b888a 100644
--- a/test/core/end2end/tests/disappearing_server.c
+++ b/test/core/end2end/tests/disappearing_server.c
@@ -45,16 +45,18 @@
 
 static void *tag(intptr_t t) { return (void *)t; }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -84,7 +86,6 @@
                                            cq_verifier *cqv) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   grpc_op ops[6];
   grpc_op *op;
   grpc_metadata_array initial_metadata_recv;
@@ -96,6 +97,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/empty_batch.c b/test/core/end2end/tests/empty_batch.c
index 50bb6b8..37ca813 100644
--- a/test/core/end2end/tests/empty_batch.c
+++ b/test/core/end2end/tests/empty_batch.c
@@ -59,16 +59,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -100,11 +102,11 @@
 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;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c
index ebfe3b0..0c4f0dd 100644
--- a/test/core/end2end/tests/filter_call_init_fails.c
+++ b/test/core/end2end/tests/filter_call_init_fails.c
@@ -49,7 +49,9 @@
 
 enum { TIMEOUT = 200000 };
 
-static bool g_enable_filter = false;
+static bool g_enable_server_channel_filter = false;
+static bool g_enable_client_channel_filter = false;
+static bool g_enable_client_subchannel_filter = false;
 
 static void *tag(intptr_t t) { return (void *)t; }
 
@@ -65,16 +67,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -103,16 +107,15 @@
   grpc_completion_queue_destroy(f->cq);
 }
 
-// Simple request via a server filter that always fails to initialize
-// the call.
-static void test_request(grpc_end2end_test_config config) {
+// Simple request via a SERVER_CHANNEL filter that always fails to
+// initialize the call.
+static void test_server_channel_filter(grpc_end2end_test_config config) {
   grpc_call *c;
   grpc_call *s;
   grpc_slice request_payload_slice =
       grpc_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_end2end_test_fixture f =
       begin_test(config, "filter_call_init_fails", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -127,6 +130,7 @@
   grpc_call_error error;
   grpc_slice details;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
@@ -199,6 +203,211 @@
   config.tear_down_data(&f);
 }
 
+// Simple request via a CLIENT_CHANNEL or CLIENT_DIRECT_CHANNEL filter
+// that always fails to initialize the call.
+static void test_client_channel_filter(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_slice request_payload_slice =
+      grpc_slice_from_copied_string("hello world");
+  grpc_byte_buffer *request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_from_now();
+  grpc_end2end_test_fixture f =
+      begin_test(config, "filter_call_init_fails", NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_byte_buffer *request_payload_recv = NULL;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/foo"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      NULL);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->data.send_initial_metadata.metadata = NULL;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "access denied"));
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(cqv);
+
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+// Simple request via a CLIENT_SUBCHANNEL filter that always fails to
+// initialize the call.
+static void test_client_subchannel_filter(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_slice request_payload_slice =
+      grpc_slice_from_copied_string("hello world");
+  grpc_byte_buffer *request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_from_now();
+  grpc_end2end_test_fixture f =
+      begin_test(config, "filter_call_init_fails", NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_byte_buffer *request_payload_recv = NULL;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/foo"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      NULL);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->data.send_initial_metadata.metadata = NULL;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "access denied"));
+
+  // Reset and create a new call.  (The first call uses a different code
+  // path in client_channel.c than subsequent calls on the same channel,
+  // and we need to test both.)
+  grpc_call_destroy(c);
+  status = GRPC_STATUS_OK;
+  grpc_slice_unref(details);
+  details = grpc_empty_slice();
+
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/foo"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      NULL);
+  GPR_ASSERT(c);
+
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "access denied"));
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(cqv);
+
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
 /*******************************************************************************
  * Test filter - always fails to initialize a call
  */
@@ -242,9 +451,10 @@
  * Registration
  */
 
-static bool maybe_add_filter(grpc_exec_ctx *exec_ctx,
-                             grpc_channel_stack_builder *builder, void *arg) {
-  if (g_enable_filter) {
+static bool maybe_add_server_channel_filter(grpc_exec_ctx *exec_ctx,
+                                            grpc_channel_stack_builder *builder,
+                                            void *arg) {
+  if (g_enable_server_channel_filter) {
     // Want to add the filter as close to the end as possible, to make
     // sure that all of the filters work well together.  However, we
     // can't add it at the very end, because the connected channel filter
@@ -261,17 +471,73 @@
   }
 }
 
+static bool maybe_add_client_channel_filter(grpc_exec_ctx *exec_ctx,
+                                            grpc_channel_stack_builder *builder,
+                                            void *arg) {
+  if (g_enable_client_channel_filter) {
+    // Want to add the filter as close to the end as possible, to make
+    // sure that all of the filters work well together.  However, we
+    // can't add it at the very end, because the connected channel filter
+    // must be the last one.  So we add it right before the last one.
+    grpc_channel_stack_builder_iterator *it =
+        grpc_channel_stack_builder_create_iterator_at_last(builder);
+    GPR_ASSERT(grpc_channel_stack_builder_move_prev(it));
+    const bool retval = grpc_channel_stack_builder_add_filter_before(
+        it, &test_filter, NULL, NULL);
+    grpc_channel_stack_builder_iterator_destroy(it);
+    return retval;
+  } else {
+    return true;
+  }
+}
+
+static bool maybe_add_client_subchannel_filter(
+    grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, void *arg) {
+  if (g_enable_client_subchannel_filter) {
+    // Want to add the filter as close to the end as possible, to make
+    // sure that all of the filters work well together.  However, we
+    // can't add it at the very end, because the client channel filter
+    // must be the last one.  So we add it right before the last one.
+    grpc_channel_stack_builder_iterator *it =
+        grpc_channel_stack_builder_create_iterator_at_last(builder);
+    GPR_ASSERT(grpc_channel_stack_builder_move_prev(it));
+    const bool retval = grpc_channel_stack_builder_add_filter_before(
+        it, &test_filter, NULL, NULL);
+    grpc_channel_stack_builder_iterator_destroy(it);
+    return retval;
+  } else {
+    return true;
+  }
+}
+
 static void init_plugin(void) {
   grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
-                                   maybe_add_filter, NULL);
+                                   maybe_add_server_channel_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX,
+                                   maybe_add_client_channel_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX,
+                                   maybe_add_client_subchannel_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX,
+                                   maybe_add_client_channel_filter, NULL);
 }
 
 static void destroy_plugin(void) {}
 
 void filter_call_init_fails(grpc_end2end_test_config config) {
-  g_enable_filter = true;
-  test_request(config);
-  g_enable_filter = false;
+  gpr_log(GPR_INFO, "Testing SERVER_CHANNEL filter.");
+  g_enable_server_channel_filter = true;
+  test_server_channel_filter(config);
+  g_enable_server_channel_filter = false;
+  gpr_log(GPR_INFO, "Testing CLIENT_CHANNEL / CLIENT_DIRECT_CHANNEL filter.");
+  g_enable_client_channel_filter = true;
+  test_client_channel_filter(config);
+  g_enable_client_channel_filter = false;
+  if (config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL) {
+    gpr_log(GPR_INFO, "Testing CLIENT_SUBCHANNEL filter.");
+    g_enable_client_subchannel_filter = true;
+    test_client_subchannel_filter(config);
+    g_enable_client_subchannel_filter = false;
+  }
 }
 
 void filter_call_init_fails_pre_init(void) {
diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c
index e6b02ea..9115823 100644
--- a/test/core/end2end/tests/filter_causes_close.c
+++ b/test/core/end2end/tests/filter_causes_close.c
@@ -62,16 +62,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -108,7 +110,6 @@
       grpc_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_end2end_test_fixture f =
       begin_test(config, "filter_causes_close", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -123,6 +124,7 @@
   grpc_call_error error;
   grpc_slice details;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
@@ -216,13 +218,14 @@
                          GRPC_STATUS_PERMISSION_DENIED));
 }
 
-static void start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                      grpc_call_element *elem,
-                                      grpc_transport_stream_op *op) {
+static void start_transport_stream_op_batch(
+    grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+    grpc_transport_stream_op_batch *op) {
   call_data *calld = elem->call_data;
-  if (op->recv_initial_metadata != NULL) {
-    calld->recv_im_ready = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready =
+  if (op->recv_initial_metadata) {
+    calld->recv_im_ready =
+        op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+    op->payload->recv_initial_metadata.recv_initial_metadata_ready =
         grpc_closure_create(recv_im_ready, elem, grpc_schedule_on_exec_ctx);
   }
   grpc_call_next_op(exec_ctx, elem, op);
@@ -248,7 +251,7 @@
                                  grpc_channel_element *elem) {}
 
 static const grpc_channel_filter test_filter = {
-    start_transport_stream_op,
+    start_transport_stream_op_batch,
     grpc_channel_next_op,
     sizeof(call_data),
     init_call_elem,
diff --git a/test/core/end2end/tests/filter_latency.c b/test/core/end2end/tests/filter_latency.c
index 2428c92..d38ce22 100644
--- a/test/core/end2end/tests/filter_latency.c
+++ b/test/core/end2end/tests/filter_latency.c
@@ -69,16 +69,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -115,7 +117,6 @@
       grpc_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_end2end_test_fixture f =
       begin_test(config, "filter_latency", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -137,6 +138,7 @@
   gpr_mu_unlock(&g_mu);
   const gpr_timespec start_time = gpr_now(GPR_CLOCK_MONOTONIC);
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/graceful_server_shutdown.c b/test/core/end2end/tests/graceful_server_shutdown.c
index a3ad260..182bb20 100644
--- a/test/core/end2end/tests/graceful_server_shutdown.c
+++ b/test/core/end2end/tests/graceful_server_shutdown.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -95,7 +97,6 @@
     grpc_end2end_test_config config) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = n_seconds_time(10);
   grpc_end2end_test_fixture f = begin_test(
       config, "test_early_server_shutdown_finishes_inflight_calls", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -110,6 +111,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = n_seconds_from_now(10);
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/high_initial_seqno.c b/test/core/end2end/tests/high_initial_seqno.c
index cca8532..f534a19 100644
--- a/test/core/end2end/tests/high_initial_seqno.c
+++ b/test/core/end2end/tests/high_initial_seqno.c
@@ -61,16 +61,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -103,7 +105,6 @@
                                 grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -116,6 +117,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/hpack_size.c b/test/core/end2end/tests/hpack_size.c
index 7601722..17ef204 100644
--- a/test/core/end2end/tests/hpack_size.c
+++ b/test/core/end2end/tests/hpack_size.c
@@ -201,16 +201,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -243,7 +245,6 @@
                                 grpc_end2end_test_fixture f, size_t index) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -268,6 +269,7 @@
   extra_metadata[2].value =
       grpc_slice_from_static_string(dragons[index % GPR_ARRAY_SIZE(dragons)]);
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/idempotent_request.c b/test/core/end2end/tests/idempotent_request.c
index cef2e10..f80654d 100644
--- a/test/core/end2end/tests/idempotent_request.c
+++ b/test/core/end2end/tests/idempotent_request.c
@@ -59,16 +59,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -101,7 +103,6 @@
                                 grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -115,6 +116,7 @@
   int was_cancelled = 2;
   char *peer;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/invoke_large_request.c b/test/core/end2end/tests/invoke_large_request.c
index d799bd8..f4b93d9 100644
--- a/test/core/end2end/tests/invoke_large_request.c
+++ b/test/core/end2end/tests/invoke_large_request.c
@@ -58,14 +58,14 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, n_seconds_time(5), NULL);
+    ev = grpc_completion_queue_next(cq, n_seconds_from_now(5), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -128,7 +128,6 @@
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
-  gpr_timespec deadline = n_seconds_time(30);
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -143,6 +142,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = n_seconds_from_now(30);
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/keepalive_timeout.c b/test/core/end2end/tests/keepalive_timeout.c
index 44b6e12..bf6ca0d 100644
--- a/test/core/end2end/tests/keepalive_timeout.c
+++ b/test/core/end2end/tests/keepalive_timeout.c
@@ -61,25 +61,27 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
 static void shutdown_server(grpc_end2end_test_fixture *f) {
   if (!f->server) return;
   grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
-  GPR_ASSERT(
-      grpc_completion_queue_pluck(f->cq, tag(1000), five_seconds_time(), NULL)
-          .type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
+                                         five_seconds_from_now(), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -108,13 +110,12 @@
       grpc_slice_from_copied_string("hello world");
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
 
   grpc_arg keepalive_args[] = {{.type = GRPC_ARG_INTEGER,
-                                .key = GRPC_ARG_CLIENT_KEEPALIVE_TIME_S,
-                                .value.integer = 2},
+                                .key = GRPC_ARG_KEEPALIVE_TIME_MS,
+                                .value.integer = 1500},
                                {.type = GRPC_ARG_INTEGER,
-                                .key = GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S,
+                                .key = GRPC_ARG_KEEPALIVE_TIMEOUT_MS,
                                 .value.integer = 0},
                                {.type = GRPC_ARG_INTEGER,
                                 .key = GRPC_ARG_HTTP2_BDP_PROBE,
@@ -140,6 +141,7 @@
   /* Disable ping ack to trigger the keepalive timeout */
   grpc_set_disable_ping_ack(true);
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/large_metadata.c b/test/core/end2end/tests/large_metadata.c
index ac4c0e7..a670e41 100644
--- a/test/core/end2end/tests/large_metadata.c
+++ b/test/core/end2end/tests/large_metadata.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -103,7 +105,6 @@
       grpc_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_metadata meta;
   const size_t large_size = 64 * 1024;
   grpc_arg arg = {GRPC_ARG_INTEGER,
@@ -125,6 +126,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/load_reporting_hook.c b/test/core/end2end/tests/load_reporting_hook.c
index d1ee26f..ea3dd23 100644
--- a/test/core/end2end/tests/load_reporting_hook.c
+++ b/test/core/end2end/tests/load_reporting_hook.c
@@ -41,8 +41,8 @@
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/ext/load_reporting/load_reporting.h"
-#include "src/core/ext/load_reporting/load_reporting_filter.h"
+#include "src/core/ext/filters/load_reporting/load_reporting.h"
+#include "src/core/ext/filters/load_reporting/load_reporting_filter.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/transport/static_metadata.h"
 
@@ -84,16 +84,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -136,7 +138,6 @@
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -151,6 +152,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string(method_name),
diff --git a/test/core/end2end/tests/max_concurrent_streams.c b/test/core/end2end/tests/max_concurrent_streams.c
index e81a628..2360138 100644
--- a/test/core/end2end/tests/max_concurrent_streams.c
+++ b/test/core/end2end/tests/max_concurrent_streams.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -99,7 +101,6 @@
                                 grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -112,6 +113,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
@@ -257,7 +259,7 @@
 
   /* start two requests - ensuring that the second is not accepted until
      the first completes */
-  deadline = n_seconds_time(1000);
+  deadline = n_seconds_from_now(1000);
   c1 = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/alpha"),
@@ -502,13 +504,13 @@
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/alpha"),
       get_host_override_slice("foo.test.google.fr:1234", config),
-      n_seconds_time(3), NULL);
+      n_seconds_from_now(3), NULL);
   GPR_ASSERT(c1);
   c2 = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/beta"),
       get_host_override_slice("foo.test.google.fr:1234", config),
-      n_seconds_time(1000), NULL);
+      n_seconds_from_now(1000), NULL);
   GPR_ASSERT(c2);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
@@ -697,13 +699,13 @@
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/alpha"),
       get_host_override_slice("foo.test.google.fr:1234", config),
-      n_seconds_time(1000), NULL);
+      n_seconds_from_now(1000), NULL);
   GPR_ASSERT(c1);
   c2 = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/beta"),
       get_host_override_slice("foo.test.google.fr:1234", config),
-      n_seconds_time(3), NULL);
+      n_seconds_from_now(3), NULL);
   GPR_ASSERT(c2);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
diff --git a/test/core/end2end/tests/max_connection_age.c b/test/core/end2end/tests/max_connection_age.c
index 1de54e0..04bdb39 100644
--- a/test/core/end2end/tests/max_connection_age.c
+++ b/test/core/end2end/tests/max_connection_age.c
@@ -47,6 +47,7 @@
 #define MAX_CONNECTION_AGE_GRACE_MS 1000
 #define MAX_CONNECTION_IDLE_MS 9999
 
+#define MAX_CONNECTION_AGE_JITTER_MULTIPLIER 1.1
 #define CALL_DEADLINE_S 10
 /* The amount of time we wait for the connection to time out, but after it the
    connection should not use up its grace period. It should be a number between
@@ -57,7 +58,7 @@
    should be shorter than CALL_DEADLINE_S - CQ_MAX_CONNECTION_AGE_WAIT_TIME_S */
 #define CQ_MAX_CONNECTION_AGE_GRACE_WAIT_TIME_S 2
 /* The grace period for the test to observe the channel shutdown process */
-#define IMMEDIATE_SHUTDOWN_GRACE_TIME_MS 300
+#define IMMEDIATE_SHUTDOWN_GRACE_TIME_MS 3000
 
 static void *tag(intptr_t t) { return (void *)t; }
 
@@ -169,8 +170,8 @@
   cq_verify(cqv);
 
   gpr_timespec expect_shutdown_time = grpc_timeout_milliseconds_to_deadline(
-      MAX_CONNECTION_AGE_MS + MAX_CONNECTION_AGE_GRACE_MS +
-      IMMEDIATE_SHUTDOWN_GRACE_TIME_MS);
+      (int)(MAX_CONNECTION_AGE_MS * MAX_CONNECTION_AGE_JITTER_MULTIPLIER) +
+      MAX_CONNECTION_AGE_GRACE_MS + IMMEDIATE_SHUTDOWN_GRACE_TIME_MS);
 
   /* Wait for the channel to reach its max age */
   cq_verify_empty_timeout(cqv, CQ_MAX_CONNECTION_AGE_WAIT_TIME_S);
diff --git a/test/core/end2end/tests/max_connection_idle.c b/test/core/end2end/tests/max_connection_idle.c
index 9dc1ee4..c0984e4 100644
--- a/test/core/end2end/tests/max_connection_idle.c
+++ b/test/core/end2end/tests/max_connection_idle.c
@@ -89,8 +89,8 @@
   /* wait for the channel to reach its maximum idle time */
   grpc_channel_watch_connectivity_state(
       f.client, GRPC_CHANNEL_READY,
-      grpc_timeout_milliseconds_to_deadline(MAX_CONNECTION_IDLE_MS + 500), f.cq,
-      tag(99));
+      grpc_timeout_milliseconds_to_deadline(MAX_CONNECTION_IDLE_MS + 3000),
+      f.cq, tag(99));
   CQ_EXPECT_COMPLETION(cqv, tag(99), 1);
   cq_verify(cqv);
   state = grpc_channel_check_connectivity_state(f.client, 0);
diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c
index b15d30f..ab58d9f 100644
--- a/test/core/end2end/tests/max_message_length.c
+++ b/test/core/end2end/tests/max_message_length.c
@@ -66,16 +66,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
diff --git a/test/core/end2end/tests/negative_deadline.c b/test/core/end2end/tests/negative_deadline.c
index 0b61efb..e7448bd 100644
--- a/test/core/end2end/tests/negative_deadline.c
+++ b/test/core/end2end/tests/negative_deadline.c
@@ -59,16 +59,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -100,7 +102,6 @@
 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);
   grpc_op ops[6];
   grpc_op *op;
@@ -112,6 +113,7 @@
 
   gpr_log(GPR_DEBUG, "test with %" PRIuPTR " ops", num_ops);
 
+  gpr_timespec deadline = gpr_inf_past(GPR_CLOCK_REALTIME);
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/network_status_change.c b/test/core/end2end/tests/network_status_change.c
index d7a4106..1a5f2b2 100644
--- a/test/core/end2end/tests/network_status_change.c
+++ b/test/core/end2end/tests/network_status_change.c
@@ -60,16 +60,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(500); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(500);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -106,7 +108,6 @@
       grpc_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_request_with_payload", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -122,6 +123,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/no_logging.c b/test/core/end2end/tests/no_logging.c
index 56e48a8..683d646 100644
--- a/test/core/end2end/tests/no_logging.c
+++ b/test/core/end2end/tests/no_logging.c
@@ -87,16 +87,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -129,7 +131,6 @@
                                 grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -143,6 +144,7 @@
   int was_cancelled = 2;
   char *peer;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/no_op.c b/test/core/end2end/tests/no_op.c
index 62fc728..698d8fb 100644
--- a/test/core/end2end/tests/no_op.c
+++ b/test/core/end2end/tests/no_op.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
diff --git a/test/core/end2end/tests/payload.c b/test/core/end2end/tests/payload.c
index b04ee57..5751b80 100644
--- a/test/core/end2end/tests/payload.c
+++ b/test/core/end2end/tests/payload.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -126,7 +128,6 @@
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
-  gpr_timespec deadline = n_seconds_time(60);
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -141,6 +142,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = n_seconds_from_now(60);
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/ping.c b/test/core/end2end/tests/ping.c
index 082ac64..c51c499 100644
--- a/test/core/end2end/tests/ping.c
+++ b/test/core/end2end/tests/ping.c
@@ -52,16 +52,26 @@
   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
   int i;
 
-  grpc_arg a[] = {{.type = GRPC_ARG_INTEGER,
-                   .key = GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS,
-                   .value.integer = min_time_between_pings_ms},
-                  {.type = GRPC_ARG_INTEGER,
-                   .key = GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA,
-                   .value.integer = 20}};
-  grpc_channel_args client_args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  grpc_arg client_a[] = {{.type = GRPC_ARG_INTEGER,
+                          .key = GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS,
+                          .value.integer = 0},
+                         {.type = GRPC_ARG_INTEGER,
+                          .key = GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA,
+                          .value.integer = 20}};
+  grpc_arg server_a[] = {
+      {.type = GRPC_ARG_INTEGER,
+       .key = GRPC_ARG_HTTP2_MIN_PING_INTERVAL_WITHOUT_DATA_MS,
+       .value.integer = 0},
+      {.type = GRPC_ARG_INTEGER,
+       .key = GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS,
+       .value.integer = 1}};
+  grpc_channel_args client_args = {.num_args = GPR_ARRAY_SIZE(client_a),
+                                   .args = client_a};
+  grpc_channel_args server_args = {.num_args = GPR_ARRAY_SIZE(server_a),
+                                   .args = server_a};
 
   config.init_client(&f, &client_args);
-  config.init_server(&f, NULL);
+  config.init_server(&f, &server_args);
 
   grpc_channel_ping(f.client, f.cq, tag(0), NULL);
   CQ_EXPECT_COMPLETION(cqv, tag(0), 0);
diff --git a/test/core/end2end/tests/ping_pong_streaming.c b/test/core/end2end/tests/ping_pong_streaming.c
index 848f760..cd81ce2 100644
--- a/test/core/end2end/tests/ping_pong_streaming.c
+++ b/test/core/end2end/tests/ping_pong_streaming.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -102,7 +104,6 @@
       begin_test(config, "test_pingpong_streaming", NULL, NULL);
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -124,6 +125,7 @@
   grpc_slice response_payload_slice =
       grpc_slice_from_copied_string("hello you");
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/registered_call.c b/test/core/end2end/tests/registered_call.c
index 9c8ce89..242add3 100644
--- a/test/core/end2end/tests/registered_call.c
+++ b/test/core/end2end/tests/registered_call.c
@@ -59,16 +59,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -101,7 +103,6 @@
                                 grpc_end2end_test_fixture f, void *rc) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -114,6 +115,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_registered_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, rc, deadline, NULL);
   GPR_ASSERT(c);
diff --git a/test/core/end2end/tests/request_with_flags.c b/test/core/end2end/tests/request_with_flags.c
index 329359e..10ecf5b 100644
--- a/test/core/end2end/tests/request_with_flags.c
+++ b/test/core/end2end/tests/request_with_flags.c
@@ -58,16 +58,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -104,7 +106,6 @@
       grpc_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_request_with_flags", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -120,6 +121,7 @@
   grpc_slice details;
   grpc_call_error expectation;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/request_with_payload.c b/test/core/end2end/tests/request_with_payload.c
index f71f92b..4eb3399 100644
--- a/test/core/end2end/tests/request_with_payload.c
+++ b/test/core/end2end/tests/request_with_payload.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -103,7 +105,6 @@
       grpc_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_request_with_payload", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -119,6 +120,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/resource_quota_server.c b/test/core/end2end/tests/resource_quota_server.c
index db26b44..4d3ce1c 100644
--- a/test/core/end2end/tests/resource_quota_server.c
+++ b/test/core/end2end/tests/resource_quota_server.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -195,7 +197,7 @@
         f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
         grpc_slice_from_static_string("/foo"),
         get_host_override_slice("foo.test.google.fr", config),
-        n_seconds_time(60), NULL);
+        n_seconds_from_now(60), NULL);
 
     memset(ops, 0, sizeof(ops));
     op = ops;
@@ -237,7 +239,8 @@
   while (pending_client_calls + pending_server_recv_calls +
              pending_server_end_calls >
          0) {
-    grpc_event ev = grpc_completion_queue_next(f.cq, n_seconds_time(60), NULL);
+    grpc_event ev =
+        grpc_completion_queue_next(f.cq, n_seconds_from_now(60), NULL);
     GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
 
     int ev_tag = (int)(intptr_t)ev.tag;
diff --git a/test/core/end2end/tests/server_finishes_request.c b/test/core/end2end/tests/server_finishes_request.c
index b42d170..88bc90e 100644
--- a/test/core/end2end/tests/server_finishes_request.c
+++ b/test/core/end2end/tests/server_finishes_request.c
@@ -59,16 +59,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -101,7 +103,6 @@
                                 grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -114,6 +115,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/shutdown_finishes_calls.c b/test/core/end2end/tests/shutdown_finishes_calls.c
index c019682..6f9421d 100644
--- a/test/core/end2end/tests/shutdown_finishes_calls.c
+++ b/test/core/end2end/tests/shutdown_finishes_calls.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -88,7 +90,6 @@
     grpc_end2end_test_config config) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   grpc_end2end_test_fixture f = begin_test(
       config, "test_early_server_shutdown_finishes_inflight_calls", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -103,6 +104,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/shutdown_finishes_tags.c b/test/core/end2end/tests/shutdown_finishes_tags.c
index 5540d2a..51a2423 100644
--- a/test/core/end2end/tests/shutdown_finishes_tags.c
+++ b/test/core/end2end/tests/shutdown_finishes_tags.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
diff --git a/test/core/end2end/tests/simple_cacheable_request.c b/test/core/end2end/tests/simple_cacheable_request.c
index 4eef02e..4f1013a 100644
--- a/test/core/end2end/tests/simple_cacheable_request.c
+++ b/test/core/end2end/tests/simple_cacheable_request.c
@@ -59,16 +59,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -110,7 +112,6 @@
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_metadata meta_c[2] = {{grpc_slice_from_static_string("key1"),
                               grpc_slice_from_static_string("val1"),
                               0,
@@ -144,6 +145,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/simple_delayed_request.c b/test/core/end2end/tests/simple_delayed_request.c
index e3b6aee..978dff0 100644
--- a/test/core/end2end/tests/simple_delayed_request.c
+++ b/test/core/end2end/tests/simple_delayed_request.c
@@ -45,16 +45,18 @@
 
 static void *tag(intptr_t t) { return (void *)t; }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -90,7 +92,6 @@
                                         long delay_us) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f->cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -106,6 +107,7 @@
   config.init_client(f, client_args);
   config.init_server(f, server_args);
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/simple_metadata.c b/test/core/end2end/tests/simple_metadata.c
index 7ab5563..83d1037 100644
--- a/test/core/end2end/tests/simple_metadata.c
+++ b/test/core/end2end/tests/simple_metadata.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -108,7 +110,6 @@
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_metadata meta_c[2] = {{grpc_slice_from_static_string("key1"),
                               grpc_slice_from_static_string("val1"),
                               0,
@@ -141,6 +142,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c
index af5d749..31bfef4 100644
--- a/test/core/end2end/tests/simple_request.c
+++ b/test/core/end2end/tests/simple_request.c
@@ -59,16 +59,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -101,7 +103,6 @@
                                 grpc_end2end_test_fixture f) {
   grpc_call *c;
   grpc_call *s;
-  gpr_timespec deadline = five_seconds_time();
   cq_verifier *cqv = cq_verifier_create(f.cq);
   grpc_op ops[6];
   grpc_op *op;
@@ -115,6 +116,7 @@
   int was_cancelled = 2;
   char *peer;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/streaming_error_response.c b/test/core/end2end/tests/streaming_error_response.c
index 2b9c404..c652d94 100644
--- a/test/core/end2end/tests/streaming_error_response.c
+++ b/test/core/end2end/tests/streaming_error_response.c
@@ -62,16 +62,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -110,7 +112,6 @@
   grpc_slice response_payload2_slice = grpc_slice_from_copied_string("world");
   grpc_byte_buffer *response_payload2 =
       grpc_raw_byte_buffer_create(&response_payload2_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_end2end_test_fixture f = begin_test(config, "streaming_error_response",
                                            NULL, NULL, request_status_early);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -127,6 +128,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/trailing_metadata.c b/test/core/end2end/tests/trailing_metadata.c
index dbbda50..3cbffdf 100644
--- a/test/core/end2end/tests/trailing_metadata.c
+++ b/test/core/end2end/tests/trailing_metadata.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -108,7 +110,6 @@
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
   grpc_byte_buffer *response_payload =
       grpc_raw_byte_buffer_create(&response_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_metadata meta_c[2] = {{grpc_slice_from_static_string("key1"),
                               grpc_slice_from_static_string("val1"),
                               0,
@@ -149,6 +150,7 @@
   grpc_slice details;
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/write_buffering.c b/test/core/end2end/tests/write_buffering.c
index abf90ca..2d4142b 100644
--- a/test/core/end2end/tests/write_buffering.c
+++ b/test/core/end2end/tests/write_buffering.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -106,7 +108,6 @@
   grpc_slice request_payload_slice2 = grpc_slice_from_copied_string("abc123");
   grpc_byte_buffer *request_payload2 =
       grpc_raw_byte_buffer_create(&request_payload_slice2, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_request_with_payload", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -123,6 +124,7 @@
   grpc_slice details = grpc_empty_slice();
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/end2end/tests/write_buffering_at_end.c b/test/core/end2end/tests/write_buffering_at_end.c
index 8c02b42..e61343e 100644
--- a/test/core/end2end/tests/write_buffering_at_end.c
+++ b/test/core/end2end/tests/write_buffering_at_end.c
@@ -57,16 +57,18 @@
   return f;
 }
 
-static gpr_timespec n_seconds_time(int n) {
+static gpr_timespec n_seconds_from_now(int n) {
   return grpc_timeout_seconds_to_deadline(n);
 }
 
-static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
 
 static void drain_cq(grpc_completion_queue *cq) {
   grpc_event ev;
   do {
-    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), NULL);
   } while (ev.type != GRPC_QUEUE_SHUTDOWN);
 }
 
@@ -103,7 +105,6 @@
       grpc_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  gpr_timespec deadline = five_seconds_time();
   grpc_end2end_test_fixture f =
       begin_test(config, "test_invoke_request_with_payload", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
@@ -120,6 +121,7 @@
   grpc_slice details = grpc_empty_slice();
   int was_cancelled = 2;
 
+  gpr_timespec deadline = five_seconds_from_now();
   c = grpc_channel_create_call(
       f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
       grpc_slice_from_static_string("/foo"),
diff --git a/test/core/iomgr/endpoint_pair_test.c b/test/core/iomgr/endpoint_pair_test.c
index 4b98ef2..c8a6077 100644
--- a/test/core/iomgr/endpoint_pair_test.c
+++ b/test/core/iomgr/endpoint_pair_test.c
@@ -49,11 +49,11 @@
     size_t slice_size) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_endpoint_test_fixture f;
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("endpoint_pair_test");
-  grpc_endpoint_pair p =
-      grpc_iomgr_create_endpoint_pair("test", resource_quota, slice_size);
-  grpc_resource_quota_unref(resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  grpc_endpoint_pair p = grpc_iomgr_create_endpoint_pair("test", &args);
 
   f.client_ep = p.client;
   f.server_ep = p.server;
diff --git a/test/core/iomgr/error_test.c b/test/core/iomgr/error_test.c
index 5c60a4d..607dbee 100644
--- a/test/core/iomgr/error_test.c
+++ b/test/core/iomgr/error_test.c
@@ -182,8 +182,6 @@
   grpc_error* parent =
       GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Parent", children, 2);
 
-  gpr_log(GPR_DEBUG, "%s", grpc_error_string(parent));
-
   for (size_t i = 0; i < 2; ++i) {
     GRPC_ERROR_UNREF(children[i]);
   }
@@ -216,6 +214,33 @@
   GRPC_ERROR_UNREF(error);
 }
 
+static void test_overflow() {
+  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Overflow");
+
+  for (size_t i = 0; i < 150; ++i) {
+    error = grpc_error_add_child(error,
+                                 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Child"));
+  }
+
+  error = grpc_error_set_int(error, GRPC_ERROR_INT_HTTP2_ERROR, 5);
+  error =
+      grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE,
+                         grpc_slice_from_static_string("message for child 2"));
+  error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, 5);
+
+  intptr_t i;
+  GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_HTTP2_ERROR, &i));
+  GPR_ASSERT(i == 5);
+  GPR_ASSERT(!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &i));
+
+  error = grpc_error_set_int(error, GRPC_ERROR_INT_HTTP2_ERROR, 10);
+  GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_HTTP2_ERROR, &i));
+  GPR_ASSERT(i == 10);
+
+  GRPC_ERROR_UNREF(error);
+  ;
+}
+
 int main(int argc, char** argv) {
   grpc_test_init(argc, argv);
   grpc_init();
@@ -228,6 +253,7 @@
   test_create_referencing();
   test_create_referencing_many();
   test_special();
+  test_overflow();
   grpc_shutdown();
 
   return 0;
diff --git a/test/core/iomgr/fd_conservation_posix_test.c b/test/core/iomgr/fd_conservation_posix_test.c
index 3dffa02..6ac322b 100644
--- a/test/core/iomgr/fd_conservation_posix_test.c
+++ b/test/core/iomgr/fd_conservation_posix_test.c
@@ -57,7 +57,7 @@
 
   for (i = 0; i < 100; i++) {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    p = grpc_iomgr_create_endpoint_pair("test", resource_quota, 1);
+    p = grpc_iomgr_create_endpoint_pair("test", NULL);
     grpc_endpoint_destroy(&exec_ctx, p.client);
     grpc_endpoint_destroy(&exec_ctx, p.server);
     grpc_exec_ctx_finish(&exec_ctx);
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index 5a55be8..2c53a00 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -183,10 +183,12 @@
 
   create_sockets(sv);
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create("read_test");
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), resource_quota,
-                       slice_size, "test");
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  ep = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], "read_test"), &args,
+                       "test");
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   written_bytes = fill_socket_partial(sv[0], num_bytes);
@@ -233,11 +235,12 @@
 
   create_sockets(sv);
 
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("large_read_test");
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), resource_quota,
-                       slice_size, "test");
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  ep = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], "large_read_test"),
+                       &args, "test");
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   written_bytes = fill_socket(sv[0]);
@@ -372,11 +375,12 @@
 
   create_sockets(sv);
 
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("write_test");
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"), resource_quota,
-                       GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "test");
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  ep = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], "write_test"), &args,
+                       "test");
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   state.ep = ep;
@@ -441,12 +445,13 @@
 
   create_sockets(sv);
 
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("release_fd_test");
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), resource_quota,
-                       slice_size, "test");
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  ep = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], "read_test"), &args,
+                       "test");
   GPR_ASSERT(grpc_tcp_fd(ep) == sv[1] && sv[1] >= 0);
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   written_bytes = fill_socket_partial(sv[0], num_bytes);
@@ -534,10 +539,14 @@
   create_sockets(sv);
   grpc_resource_quota *resource_quota =
       grpc_resource_quota_create("tcp_posix_test_socketpair");
-  f.client_ep = grpc_tcp_create(grpc_fd_create(sv[0], "fixture:client"),
-                                resource_quota, slice_size, "test");
-  f.server_ep = grpc_tcp_create(grpc_fd_create(sv[1], "fixture:server"),
-                                resource_quota, slice_size, "test");
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  f.client_ep = grpc_tcp_create(
+      &exec_ctx, grpc_fd_create(sv[0], "fixture:client"), &args, "test");
+  f.server_ep = grpc_tcp_create(
+      &exec_ctx, grpc_fd_create(sv[1], "fixture:server"), &args, "test");
   grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_endpoint_add_to_pollset(&exec_ctx, f.client_ep, g_pollset);
   grpc_endpoint_add_to_pollset(&exec_ctx, f.server_ep, g_pollset);
diff --git a/test/core/iomgr/timer_heap_test.c b/test/core/iomgr/timer_heap_test.c
index 410d972..153304f 100644
--- a/test/core/iomgr/timer_heap_test.c
+++ b/test/core/iomgr/timer_heap_test.c
@@ -47,13 +47,7 @@
 
 #include "test/core/util/test_config.h"
 
-static gpr_timespec random_deadline(void) {
-  gpr_timespec ts;
-  ts.tv_sec = rand();
-  ts.tv_nsec = rand();
-  ts.clock_type = GPR_CLOCK_REALTIME;
-  return ts;
-}
+static gpr_atm random_deadline(void) { return rand(); }
 
 static grpc_timer *create_test_elements(size_t num_elements) {
   grpc_timer *elems = gpr_malloc(num_elements * sizeof(grpc_timer));
@@ -78,12 +72,10 @@
     size_t left_child = 1u + 2u * i;
     size_t right_child = left_child + 1u;
     if (left_child < pq->timer_count) {
-      GPR_ASSERT(gpr_time_cmp(pq->timers[i]->deadline,
-                              pq->timers[left_child]->deadline) <= 0);
+      GPR_ASSERT(pq->timers[i]->deadline <= pq->timers[left_child]->deadline);
     }
     if (right_child < pq->timer_count) {
-      GPR_ASSERT(gpr_time_cmp(pq->timers[i]->deadline,
-                              pq->timers[right_child]->deadline) <= 0);
+      GPR_ASSERT(pq->timers[i]->deadline <= pq->timers[right_child]->deadline);
     }
   }
 }
@@ -227,20 +219,19 @@
     }
 
     if (num_inserted) {
-      gpr_timespec *min_deadline = NULL;
+      gpr_atm *min_deadline = NULL;
       for (size_t i = 0; i < elems_size; i++) {
         if (elems[i].inserted) {
           if (min_deadline == NULL) {
             min_deadline = &elems[i].elem.deadline;
           } else {
-            if (gpr_time_cmp(elems[i].elem.deadline, *min_deadline) < 0) {
+            if (elems[i].elem.deadline < *min_deadline) {
               min_deadline = &elems[i].elem.deadline;
             }
           }
         }
       }
-      GPR_ASSERT(
-          0 == gpr_time_cmp(grpc_timer_heap_top(&pq)->deadline, *min_deadline));
+      GPR_ASSERT(grpc_timer_heap_top(&pq)->deadline == *min_deadline);
     }
   }
 
diff --git a/test/core/iomgr/timer_list_test.c b/test/core/iomgr/timer_list_test.c
index 85ad527..46e41dd 100644
--- a/test/core/iomgr/timer_list_test.c
+++ b/test/core/iomgr/timer_list_test.c
@@ -45,6 +45,9 @@
 
 #define MAX_CB 30
 
+extern int grpc_timer_trace;
+extern int grpc_timer_check_trace;
+
 static int cb_called[MAX_CB][2];
 
 static void cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
@@ -57,7 +60,11 @@
   grpc_timer timers[20];
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
+  gpr_log(GPR_INFO, "add_test");
+
   grpc_timer_list_init(start);
+  grpc_timer_trace = 1;
+  grpc_timer_check_trace = 1;
   memset(cb_called, 0, sizeof(cb_called));
 
   /* 10 ms timers.  will expire in the current epoch */
@@ -120,9 +127,7 @@
 }
 
 static gpr_timespec tfm(int m) {
-  gpr_timespec t = gpr_time_from_millis(m, GPR_TIMESPAN);
-  t.clock_type = GPR_CLOCK_REALTIME;
-  return t;
+  return gpr_time_from_millis(m, GPR_CLOCK_REALTIME);
 }
 
 /* Cleaning up a list with pending timers. */
@@ -130,7 +135,11 @@
   grpc_timer timers[5];
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
+  gpr_log(GPR_INFO, "destruction_test");
+
   grpc_timer_list_init(gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_timer_trace = 1;
+  grpc_timer_check_trace = 1;
   memset(cb_called, 0, sizeof(cb_called));
 
   grpc_timer_init(
@@ -170,6 +179,7 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
+  gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
   add_test();
   destruction_test();
   return 0;
diff --git a/test/core/nanopb/fuzzer_response.c b/test/core/nanopb/fuzzer_response.c
index 202c120..35c0efe 100644
--- a/test/core/nanopb/fuzzer_response.c
+++ b/test/core/nanopb/fuzzer_response.c
@@ -36,7 +36,7 @@
 
 #include <grpc/support/alloc.h>
 
-#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h"
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
 
 bool squelch = true;
 bool leak_check = true;
diff --git a/test/core/nanopb/fuzzer_serverlist.c b/test/core/nanopb/fuzzer_serverlist.c
index b225ae0..e1df401 100644
--- a/test/core/nanopb/fuzzer_serverlist.c
+++ b/test/core/nanopb/fuzzer_serverlist.c
@@ -36,7 +36,7 @@
 
 #include <grpc/support/alloc.h>
 
-#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h"
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
 
 bool squelch = true;
 bool leak_check = true;
diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c
index 8f11f98..71d8057 100644
--- a/test/core/security/secure_endpoint_test.c
+++ b/test/core/security/secure_endpoint_test.c
@@ -39,6 +39,7 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/useful.h>
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/security/transport/secure_endpoint.h"
@@ -57,10 +58,11 @@
   grpc_endpoint_test_fixture f;
   grpc_endpoint_pair tcp;
 
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("secure_endpoint_test");
-  tcp = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, slice_size);
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  tcp = grpc_iomgr_create_endpoint_pair("fixture", &args);
   grpc_endpoint_add_to_pollset(&exec_ctx, tcp.client, g_pollset);
   grpc_endpoint_add_to_pollset(&exec_ctx, tcp.server, g_pollset);
 
diff --git a/test/core/support/arena_test.c b/test/core/support/arena_test.c
index 35b2bbd..9eba8a0 100644
--- a/test/core/support/arena_test.c
+++ b/test/core/support/arena_test.c
@@ -83,9 +83,13 @@
   static const size_t allocs_##name[] = {__VA_ARGS__}; \
   test(#name, init_size, allocs_##name, GPR_ARRAY_SIZE(allocs_##name))
 
-#define CONCURRENT_TEST_ITERATIONS 100000
 #define CONCURRENT_TEST_THREADS 100
 
+size_t concurrent_test_iterations() {
+  if (sizeof(void *) < 8) return 1000;
+  return 100000;
+}
+
 typedef struct {
   gpr_event ev_start;
   gpr_arena *arena;
@@ -94,7 +98,7 @@
 static void concurrent_test_body(void *arg) {
   concurrent_test_args *a = arg;
   gpr_event_wait(&a->ev_start, gpr_inf_future(GPR_CLOCK_REALTIME));
-  for (size_t i = 0; i < CONCURRENT_TEST_ITERATIONS; i++) {
+  for (size_t i = 0; i < concurrent_test_iterations(); i++) {
     *(char *)gpr_arena_alloc(a->arena, 1) = (char)i;
   }
 }
diff --git a/test/core/surface/channel_create_test.c b/test/core/surface/channel_create_test.c
index 654e532..21bf6a0 100644
--- a/test/core/surface/channel_create_test.c
+++ b/test/core/surface/channel_create_test.c
@@ -36,7 +36,7 @@
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
 
-#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/surface/channel.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/surface/secure_channel_create_test.c b/test/core/surface/secure_channel_create_test.c
index 567f8ae..adb956c 100644
--- a/test/core/surface/secure_channel_create_test.c
+++ b/test/core/surface/secure_channel_create_test.c
@@ -36,7 +36,7 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/log.h>
-#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 #include "src/core/lib/security/transport/security_connector.h"
 #include "src/core/lib/surface/channel.h"
diff --git a/test/core/util/debugger_macros.c b/test/core/util/debugger_macros.c
index de6a2f3..af61d93 100644
--- a/test/core/util/debugger_macros.c
+++ b/test/core/util/debugger_macros.c
@@ -39,7 +39,7 @@
 
 #include <stdio.h>
 
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/surface/call.h"
diff --git a/test/cpp/end2end/filter_end2end_test.cc b/test/cpp/end2end/filter_end2end_test.cc
index bd384f6..2f873ee 100644
--- a/test/cpp/end2end/filter_end2end_test.cc
+++ b/test/cpp/end2end/filter_end2end_test.cc
@@ -122,8 +122,9 @@
 
 class CallDataImpl : public CallData {
  public:
-  void StartTransportStreamOp(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
-                              TransportStreamOp* op) override {
+  void StartTransportStreamOpBatch(grpc_exec_ctx* exec_ctx,
+                                   grpc_call_element* elem,
+                                   TransportStreamOpBatch* op) override {
     // Incrementing the counter could be done from Init(), but we want
     // to test that the individual methods are actually called correctly.
     if (op->recv_initial_metadata() != nullptr) IncrementCallCounter();
diff --git a/test/cpp/grpclb/grpclb_api_test.cc b/test/cpp/grpclb/grpclb_api_test.cc
index 82ccf43..d9df2bb 100644
--- a/test/cpp/grpclb/grpclb_api_test.cc
+++ b/test/cpp/grpclb/grpclb_api_test.cc
@@ -34,7 +34,7 @@
 #include <grpc++/impl/codegen/config.h>
 #include <gtest/gtest.h>
 
-#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h"
+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/proto/grpc/lb/v1/load_balancer.pb.h"  // C++ version
diff --git a/test/cpp/grpclb/grpclb_test.cc b/test/cpp/grpclb/grpclb_test.cc
index 89ed924..eb3e5b6 100644
--- a/test/cpp/grpclb/grpclb_test.cc
+++ b/test/cpp/grpclb/grpclb_test.cc
@@ -51,7 +51,7 @@
 
 #include <grpc++/impl/codegen/config.h>
 extern "C" {
-#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/iomgr/sockaddr.h"
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index 5688ab7..369413e 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -99,6 +99,7 @@
 
 using grpc::testing::CreateChannelForTestCase;
 using grpc::testing::GetServiceAccountJsonKey;
+using grpc::testing::UpdateActions;
 
 int main(int argc, char** argv) {
   grpc::testing::InitTest(&argc, &argv, true);
@@ -165,6 +166,8 @@
   // actions["cacheable_unary"] =
   //    std::bind(&grpc::testing::InteropClient::DoCacheableUnary, &client);
 
+  UpdateActions(&actions);
+
   if (FLAGS_test_case == "all") {
     for (const auto& action : actions) {
       action.second();
diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc
index d3192ad..784cd28 100644
--- a/test/cpp/interop/client_helper.cc
+++ b/test/cpp/interop/client_helper.cc
@@ -89,6 +89,9 @@
   return access_token;
 }
 
+void UpdateActions(
+    std::unordered_map<grpc::string, std::function<bool()>>* actions) {}
+
 std::shared_ptr<Channel> CreateChannelForTestCase(
     const grpc::string& test_case) {
   GPR_ASSERT(FLAGS_server_port);
diff --git a/test/cpp/interop/client_helper.h b/test/cpp/interop/client_helper.h
index 622b96e..387530a 100644
--- a/test/cpp/interop/client_helper.h
+++ b/test/cpp/interop/client_helper.h
@@ -35,6 +35,7 @@
 #define GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H
 
 #include <memory>
+#include <unordered_map>
 
 #include <grpc++/channel.h>
 
@@ -47,6 +48,9 @@
 
 grpc::string GetOauth2AccessToken();
 
+void UpdateActions(
+    std::unordered_map<grpc::string, std::function<bool()>>* actions);
+
 std::shared_ptr<Channel> CreateChannelForTestCase(
     const grpc::string& test_case);
 
diff --git a/test/cpp/microbenchmarks/BUILD b/test/cpp/microbenchmarks/BUILD
index 3861966..cae3fa1 100644
--- a/test/cpp/microbenchmarks/BUILD
+++ b/test/cpp/microbenchmarks/BUILD
@@ -32,16 +32,25 @@
 cc_test(
     name = "noop-benchmark",
     srcs = ["noop-benchmark.cc"],
-    deps = ["//external:benchmark"],
     linkopts = ["-pthread"],
+    deps = ["//external:benchmark"],
 )
 
 cc_library(
     name = "helpers",
     srcs = ["helpers.cc"],
-    hdrs = ["helpers.h", "fullstack_fixtures.h", "fullstack_context_mutators.h"],
-    deps = ["//:grpc++", "//external:benchmark", "//test/core/util:grpc_test_util", "//src/proto/grpc/testing:echo_proto"],
+    hdrs = [
+        "fullstack_context_mutators.h",
+        "fullstack_fixtures.h",
+        "helpers.h",
+    ],
     linkopts = ["-pthread"],
+    deps = [
+        "//:grpc++",
+        "//external:benchmark",
+        "//src/proto/grpc/testing:echo_proto",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 cc_test(
@@ -57,6 +66,12 @@
 )
 
 cc_test(
+    name = "bm_cq_multiple_threads",
+    srcs = ["bm_cq_multiple_threads.cc"],
+    deps = [":helpers"],
+)
+
+cc_test(
     name = "bm_error",
     srcs = ["bm_error.cc"],
     deps = [":helpers"],
@@ -66,8 +81,8 @@
     name = "bm_fullstack_streaming_ping_pong",
     srcs = ["bm_fullstack_streaming_ping_pong.cc"],
     deps = [":helpers"],
+)
 
-    )
 cc_test(
     name = "bm_fullstack_streaming_pump",
     srcs = ["bm_fullstack_streaming_pump.cc"],
diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc
index 4af2263..136b7c0 100644
--- a/test/cpp/microbenchmarks/bm_call_create.cc
+++ b/test/cpp/microbenchmarks/bm_call_create.cc
@@ -45,8 +45,8 @@
 #include <grpc/support/string_util.h>
 
 extern "C" {
-#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/load_reporting/load_reporting_filter.h"
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/load_reporting/load_reporting_filter.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/channel/compress_filter.h"
 #include "src/core/lib/channel/connected_channel.h"
@@ -54,6 +54,7 @@
 #include "src/core/lib/channel/http_client_filter.h"
 #include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/channel/message_size_filter.h"
+#include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/transport/transport_impl.h"
 }
@@ -152,6 +153,7 @@
   grpc::testing::EchoResponse recv_response;
   grpc::Status recv_status;
   while (state.KeepRunning()) {
+    GPR_TIMER_SCOPE("BenchmarkCycle", 0);
     grpc::ClientContext cli_ctx;
     auto reader = stub->AsyncEcho(&cli_ctx, send_request, &cq);
     reader->Finish(&recv_response, &recv_status, tag(0));
@@ -221,7 +223,7 @@
 
 static void StartTransportStreamOp(grpc_exec_ctx *exec_ctx,
                                    grpc_call_element *elem,
-                                   grpc_transport_stream_op *op) {}
+                                   grpc_transport_stream_op_batch *op) {}
 
 static void StartTransportOp(grpc_exec_ctx *exec_ctx,
                              grpc_channel_element *elem,
@@ -296,7 +298,7 @@
 
 /* implementation of grpc_transport_perform_stream_op */
 void PerformStreamOp(grpc_exec_ctx *exec_ctx, grpc_transport *self,
-                     grpc_stream *stream, grpc_transport_stream_op *op) {
+                     grpc_stream *stream, grpc_transport_stream_op_batch *op) {
   grpc_closure_sched(exec_ctx, op->on_complete, GRPC_ERROR_NONE);
 }
 
@@ -346,13 +348,15 @@
     memset(&op_, 0, sizeof(op_));
     op_.on_complete = grpc_closure_init(&closure_, DoNothing, nullptr,
                                         grpc_schedule_on_exec_ctx);
+    op_.send_initial_metadata = true;
+    op_.payload = &op_payload_;
   }
 
   class Op {
    public:
     Op(grpc_exec_ctx *exec_ctx, SendEmptyMetadata *p, grpc_call_stack *s) {
       grpc_metadata_batch_init(&batch_);
-      p->op_.send_initial_metadata = &batch_;
+      p->op_payload_.send_initial_metadata.send_initial_metadata = &batch_;
     }
     void Finish(grpc_exec_ctx *exec_ctx) {
       grpc_metadata_batch_destroy(exec_ctx, &batch_);
@@ -366,7 +370,8 @@
   const gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_MONOTONIC);
   const gpr_timespec start_time_ = gpr_now(GPR_CLOCK_MONOTONIC);
   const grpc_slice method_ = grpc_slice_from_static_string("/foo/bar");
-  grpc_transport_stream_op op_;
+  grpc_transport_stream_op_batch op_;
+  grpc_transport_stream_op_batch_payload op_payload_;
   grpc_closure closure_;
 };
 
@@ -426,6 +431,7 @@
   const int kArenaSize = 4096;
   call_args.arena = gpr_arena_create(kArenaSize);
   while (state.KeepRunning()) {
+    GPR_TIMER_SCOPE("BenchmarkCycle", 0);
     GRPC_ERROR_UNREF(grpc_call_stack_init(&exec_ctx, channel_stack, 1,
                                           DoNothing, NULL, &call_args));
     typename TestOp::Op op(&exec_ctx, &test_op_data, call_stack);
@@ -488,13 +494,16 @@
 
 static void StartTransportStreamOp(grpc_exec_ctx *exec_ctx,
                                    grpc_call_element *elem,
-                                   grpc_transport_stream_op *op) {
+                                   grpc_transport_stream_op_batch *op) {
   if (op->recv_initial_metadata) {
-    grpc_closure_sched(exec_ctx, op->recv_initial_metadata_ready,
-                       GRPC_ERROR_NONE);
+    grpc_closure_sched(
+        exec_ctx,
+        op->payload->recv_initial_metadata.recv_initial_metadata_ready,
+        GRPC_ERROR_NONE);
   }
   if (op->recv_message) {
-    grpc_closure_sched(exec_ctx, op->recv_message_ready, GRPC_ERROR_NONE);
+    grpc_closure_sched(exec_ctx, op->payload->recv_message.recv_message_ready,
+                       GRPC_ERROR_NONE);
   }
   grpc_closure_sched(exec_ctx, op->on_complete, GRPC_ERROR_NONE);
 }
@@ -590,6 +599,7 @@
   void *method_hdl =
       grpc_channel_register_call(fixture.channel(), "/foo/bar", NULL, NULL);
   while (state.KeepRunning()) {
+    GPR_TIMER_SCOPE("BenchmarkCycle", 0);
     grpc_call_destroy(grpc_channel_create_registered_call(
         fixture.channel(), nullptr, GRPC_PROPAGATE_DEFAULTS, fixture.cq(),
         method_hdl, deadline, NULL));
@@ -628,6 +638,7 @@
   ops[5].data.recv_status_on_client.status_details = &status_details;
   ops[5].data.recv_status_on_client.trailing_metadata = &recv_trailing_metadata;
   while (state.KeepRunning()) {
+    GPR_TIMER_SCOPE("BenchmarkCycle", 0);
     grpc_call *call = grpc_channel_create_registered_call(
         fixture.channel(), nullptr, GRPC_PROPAGATE_DEFAULTS, fixture.cq(),
         method_hdl, deadline, NULL);
@@ -670,6 +681,7 @@
   ops[0].op = GRPC_OP_SEND_MESSAGE;
   ops[0].data.send_message.send_message = send_message;
   while (state.KeepRunning()) {
+    GPR_TIMER_SCOPE("BenchmarkCycle", 0);
     grpc_call_start_batch(call, ops, 1, tag(2), NULL);
     grpc_completion_queue_next(fixture.cq(),
                                gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL);
diff --git a/test/cpp/microbenchmarks/bm_chttp2_transport.cc b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
index 254d57d..c89f349 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc
@@ -207,7 +207,7 @@
                                   static_cast<grpc_stream *>(stream_), closure);
   }
 
-  void Op(grpc_transport_stream_op *op) {
+  void Op(grpc_transport_stream_op_batch *op) {
     grpc_transport_perform_stream_op(f_->exec_ctx(), f_->transport(),
                                      static_cast<grpc_stream *>(stream_), op);
   }
@@ -305,10 +305,16 @@
   TrackCounters track_counters;
   Fixture f(grpc::ChannelArguments(), true);
   Stream s(&f);
-  grpc_transport_stream_op op;
+  grpc_transport_stream_op_batch op;
+  grpc_transport_stream_op_batch_payload op_payload;
   std::unique_ptr<Closure> start;
   std::unique_ptr<Closure> done;
 
+  auto reset_op = [&]() {
+    memset(&op, 0, sizeof(op));
+    op.payload = &op_payload;
+  };
+
   grpc_metadata_batch b;
   grpc_metadata_batch_init(&b);
   b.deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
@@ -324,14 +330,16 @@
   start = MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) {
     if (!state.KeepRunning()) return;
     s.Init(state);
-    memset(&op, 0, sizeof(op));
+    reset_op();
     op.on_complete = done.get();
-    op.send_initial_metadata = &b;
+    op.send_initial_metadata = true;
+    op.payload->send_initial_metadata.send_initial_metadata = &b;
     s.Op(&op);
   });
   done = MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) {
-    memset(&op, 0, sizeof(op));
-    op.cancel_error = GRPC_ERROR_CANCELLED;
+    reset_op();
+    op.cancel_stream = true;
+    op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
     s.Op(&op);
     s.DestroyThen(start.get());
   });
@@ -348,11 +356,16 @@
   Fixture f(grpc::ChannelArguments(), true);
   Stream s(&f);
   s.Init(state);
-  grpc_transport_stream_op op;
+  grpc_transport_stream_op_batch op;
+  grpc_transport_stream_op_batch_payload op_payload;
+  auto reset_op = [&]() {
+    memset(&op, 0, sizeof(op));
+    op.payload = &op_payload;
+  };
   std::unique_ptr<Closure> c =
       MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) {
         if (!state.KeepRunning()) return;
-        memset(&op, 0, sizeof(op));
+        reset_op();
         op.on_complete = c.get();
         s.Op(&op);
       });
@@ -370,7 +383,12 @@
   Fixture f(grpc::ChannelArguments(), true);
   Stream s(&f);
   s.Init(state);
-  grpc_transport_stream_op op;
+  grpc_transport_stream_op_batch op;
+  grpc_transport_stream_op_batch_payload op_payload;
+  auto reset_op = [&]() {
+    memset(&op, 0, sizeof(op));
+    op.payload = &op_payload;
+  };
   grpc_slice_buffer_stream send_stream;
   grpc_slice_buffer send_buffer;
   grpc_slice_buffer_init(&send_buffer);
@@ -397,20 +415,23 @@
         s.chttp2_stream()->outgoing_window_delta = 1024 * 1024 * 1024;
         f.chttp2_transport()->outgoing_window = 1024 * 1024 * 1024;
         grpc_slice_buffer_stream_init(&send_stream, &send_buffer, 0);
-        memset(&op, 0, sizeof(op));
+        reset_op();
         op.on_complete = c.get();
-        op.send_message = &send_stream.base;
+        op.send_message = true;
+        op.payload->send_message.send_message = &send_stream.base;
         s.Op(&op);
       });
 
-  memset(&op, 0, sizeof(op));
-  op.send_initial_metadata = &b;
+  reset_op();
+  op.send_initial_metadata = true;
+  op.payload->send_initial_metadata.send_initial_metadata = &b;
   op.on_complete = c.get();
   s.Op(&op);
 
   f.FlushExecCtx();
-  memset(&op, 0, sizeof(op));
-  op.cancel_error = GRPC_ERROR_CANCELLED;
+  reset_op();
+  op.cancel_stream = true;
+  op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
   s.Op(&op);
   s.DestroyThen(
       MakeOnceClosure([](grpc_exec_ctx *exec_ctx, grpc_error *error) {}));
@@ -483,10 +504,16 @@
   Fixture f(grpc::ChannelArguments(), true);
   Stream s(&f);
   s.Init(state);
-  grpc_transport_stream_op op;
+  grpc_transport_stream_op_batch_payload op_payload;
+  grpc_transport_stream_op_batch op;
   grpc_byte_stream *recv_stream;
   grpc_slice incoming_data = CreateIncomingDataSlice(state.range(0), 16384);
 
+  auto reset_op = [&]() {
+    memset(&op, 0, sizeof(op));
+    op.payload = &op_payload;
+  };
+
   grpc_metadata_batch b;
   grpc_metadata_batch_init(&b);
   grpc_metadata_batch b_recv;
@@ -518,10 +545,11 @@
         s.chttp2_stream()->incoming_window_delta = 1024 * 1024 * 1024;
         f.chttp2_transport()->incoming_window = 1024 * 1024 * 1024;
         received = 0;
-        memset(&op, 0, sizeof(op));
+        reset_op();
         op.on_complete = do_nothing.get();
-        op.recv_message = &recv_stream;
-        op.recv_message_ready = drain_start.get();
+        op.recv_message = true;
+        op.payload->recv_message.recv_message = &recv_stream;
+        op.payload->recv_message.recv_message_ready = drain_start.get();
         s.Op(&op);
         f.PushInput(grpc_slice_ref(incoming_data));
       });
@@ -552,9 +580,13 @@
     grpc_closure_run(exec_ctx, drain.get(), GRPC_ERROR_NONE);
   });
 
-  memset(&op, 0, sizeof(op));
-  op.send_initial_metadata = &b;
-  op.recv_initial_metadata = &b_recv;
+  reset_op();
+  op.send_initial_metadata = true;
+  op.payload->send_initial_metadata.send_initial_metadata = &b;
+  op.recv_initial_metadata = true;
+  op.payload->recv_initial_metadata.recv_initial_metadata = &b_recv;
+  op.payload->recv_initial_metadata.recv_initial_metadata_ready =
+      do_nothing.get();
   op.on_complete = c.get();
   s.Op(&op);
   f.PushInput(SLICE_FROM_BUFFER(
@@ -571,8 +603,9 @@
       "\x10\x14grpc-accept-encoding\x15identity,deflate,gzip"));
 
   f.FlushExecCtx();
-  memset(&op, 0, sizeof(op));
-  op.cancel_error = GRPC_ERROR_CANCELLED;
+  reset_op();
+  op.cancel_stream = true;
+  op.payload->cancel_stream.cancel_error = GRPC_ERROR_CANCELLED;
   s.Op(&op);
   s.DestroyThen(
       MakeOnceClosure([](grpc_exec_ctx *exec_ctx, grpc_error *error) {}));
diff --git a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
new file mode 100644
index 0000000..967c226
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
@@ -0,0 +1,142 @@
+/*
+ *
+ * Copyright 2017, 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 <benchmark/benchmark.h>
+#include <string.h>
+#include <atomic>
+
+#include <grpc/grpc.h>
+#include "test/cpp/microbenchmarks/helpers.h"
+
+extern "C" {
+#include "src/core/lib/iomgr/ev_posix.h"
+#include "src/core/lib/iomgr/port.h"
+#include "src/core/lib/surface/completion_queue.h"
+}
+
+struct grpc_pollset {
+  gpr_mu mu;
+};
+
+namespace grpc {
+namespace testing {
+
+static void* make_tag(int i) { return (void*)(intptr_t)i; }
+static grpc_completion_queue* g_cq;
+static grpc_event_engine_vtable g_vtable;
+
+static __thread int g_thread_idx;
+static __thread grpc_cq_completion g_cq_completion;
+
+static void pollset_shutdown(grpc_exec_ctx* exec_ctx, grpc_pollset* ps,
+                             grpc_closure* closure) {
+  grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
+}
+
+static void pollset_init(grpc_pollset* ps, gpr_mu** mu) {
+  gpr_mu_init(&ps->mu);
+  *mu = &ps->mu;
+}
+
+static void pollset_destroy(grpc_pollset* ps) { gpr_mu_destroy(&ps->mu); }
+
+static grpc_error* pollset_kick(grpc_pollset* p, grpc_pollset_worker* worker) {
+  return GRPC_ERROR_NONE;
+}
+
+/* Callback when the tag is dequeued from the completion queue. Does nothing */
+static void cq_done_cb(grpc_exec_ctx* exec_ctx, void* done_arg,
+                       grpc_cq_completion* cq_completion) {}
+
+/* Queues a completion tag. ZERO polling overhead */
+static grpc_error* pollset_work(grpc_exec_ctx* exec_ctx, grpc_pollset* ps,
+                                grpc_pollset_worker** worker, gpr_timespec now,
+                                gpr_timespec deadline) {
+  gpr_mu_unlock(&ps->mu);
+  grpc_cq_end_op(exec_ctx, g_cq, make_tag(g_thread_idx), GRPC_ERROR_NONE,
+                 cq_done_cb, NULL, &g_cq_completion);
+  grpc_exec_ctx_flush(exec_ctx);
+  gpr_mu_lock(&ps->mu);
+  return GRPC_ERROR_NONE;
+}
+
+static void init_engine_vtable() {
+  memset(&g_vtable, 0, sizeof(g_vtable));
+
+  g_vtable.pollset_size = sizeof(grpc_pollset);
+  g_vtable.pollset_init = pollset_init;
+  g_vtable.pollset_shutdown = pollset_shutdown;
+  g_vtable.pollset_destroy = pollset_destroy;
+  g_vtable.pollset_work = pollset_work;
+  g_vtable.pollset_kick = pollset_kick;
+}
+
+static void setup() {
+  grpc_init();
+  init_engine_vtable();
+  grpc_set_event_engine_test_only(&g_vtable);
+
+  g_cq = grpc_completion_queue_create(NULL);
+}
+
+static void BM_Cq_Throughput(benchmark::State& state) {
+  TrackCounters track_counters;
+  gpr_timespec deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
+
+  if (state.thread_index == 0) {
+    setup();
+  }
+
+  while (state.KeepRunning()) {
+    g_thread_idx = state.thread_index;
+    void* dummy_tag = make_tag(g_thread_idx);
+    grpc_cq_begin_op(g_cq, dummy_tag);
+    grpc_completion_queue_next(g_cq, deadline, NULL);
+  }
+
+  state.SetItemsProcessed(state.iterations());
+
+  if (state.thread_index == 0) {
+    grpc_completion_queue_shutdown(g_cq);
+    grpc_completion_queue_destroy(g_cq);
+  }
+
+  track_counters.Finish(state);
+}
+
+BENCHMARK(BM_Cq_Throughput)->ThreadRange(1, 16)->UseRealTime();
+
+}  // namespace testing
+}  // namespace grpc
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h
index dc29701..acc56bf 100644
--- a/test/cpp/microbenchmarks/fullstack_fixtures.h
+++ b/test/cpp/microbenchmarks/fullstack_fixtures.h
@@ -212,8 +212,8 @@
 class SockPair : public EndpointPairFixture {
  public:
   SockPair(Service* service)
-      : EndpointPairFixture(service, grpc_iomgr_create_endpoint_pair(
-                                         "test", Library::get().rq(), 8192)) {}
+      : EndpointPairFixture(service,
+                            grpc_iomgr_create_endpoint_pair("test", NULL)) {}
 };
 
 class InProcessCHTTP2 : public EndpointPairFixture {
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index 396d308..29a79e7 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -63,13 +63,13 @@
   virtual ~ClientRpcContext() {}
   // next state, return false if done. Collect stats when appropriate
   virtual bool RunNextState(bool, HistogramEntry* entry) = 0;
-  virtual ClientRpcContext* StartNewClone() = 0;
+  virtual void StartNewClone(CompletionQueue* cq) = 0;
   static void* tag(ClientRpcContext* c) { return reinterpret_cast<void*>(c); }
   static ClientRpcContext* detag(void* t) {
     return reinterpret_cast<ClientRpcContext*>(t);
   }
 
-  virtual void Start(CompletionQueue* cq) = 0;
+  virtual void Start(CompletionQueue* cq, const ClientConfig& config) = 0;
 };
 
 template <class RequestType, class ResponseType>
@@ -94,22 +94,17 @@
         next_issue_(next_issue),
         start_req_(start_req) {}
   ~ClientRpcContextUnaryImpl() override {}
-  void Start(CompletionQueue* cq) override {
-    cq_ = cq;
-    if (!next_issue_) {  // ready to issue
-      RunNextState(true, nullptr);
-    } else {  // wait for the issue time
-      alarm_.reset(new Alarm(cq_, next_issue_(), ClientRpcContext::tag(this)));
-    }
+  void Start(CompletionQueue* cq, const ClientConfig& config) override {
+    StartInternal(cq);
   }
   bool RunNextState(bool ok, HistogramEntry* entry) override {
     switch (next_state_) {
       case State::READY:
         start_ = UsageTimer::Now();
         response_reader_ = start_req_(stub_, &context_, req_, cq_);
+        next_state_ = State::RESP_DONE;
         response_reader_->Finish(&response_, &status_,
                                  ClientRpcContext::tag(this));
-        next_state_ = State::RESP_DONE;
         return true;
       case State::RESP_DONE:
         if (status_.ok()) {
@@ -123,9 +118,10 @@
         return false;
     }
   }
-  ClientRpcContext* StartNewClone() override {
-    return new ClientRpcContextUnaryImpl(stub_, req_, next_issue_, start_req_,
-                                         callback_);
+  void StartNewClone(CompletionQueue* cq) override {
+    auto* clone = new ClientRpcContextUnaryImpl(stub_, req_, next_issue_,
+                                                start_req_, callback_);
+    clone->StartInternal(cq);
   }
 
  private:
@@ -147,6 +143,15 @@
   double start_;
   std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>
       response_reader_;
+
+  void StartInternal(CompletionQueue* cq) {
+    cq_ = cq;
+    if (!next_issue_) {  // ready to issue
+      RunNextState(true, nullptr);
+    } else {  // wait for the issue time
+      alarm_.reset(new Alarm(cq_, next_issue_(), ClientRpcContext::tag(this)));
+    }
+  }
 };
 
 typedef std::forward_list<ClientRpcContext*> context_list;
@@ -185,7 +190,7 @@
         auto* cq = cli_cqs_[t].get();
         auto ctx =
             setup_ctx(channels_[ch].get_stub(), next_issuers_[t], request_);
-        ctx->Start(cq);
+        ctx->Start(cq, config);
       }
       t = (t + 1) % cli_cqs_.size();
     }
@@ -248,8 +253,7 @@
         } else if (!ctx->RunNextState(ok, entry)) {
           // The RPC and callback are done, so clone the ctx
           // and kickstart the new one
-          auto clone = ctx->StartNewClone();
-          clone->Start(cli_cqs_[thread_idx].get());
+          ctx->StartNewClone(cli_cqs_[thread_idx].get());
           // delete the old version
           delete ctx;
         }
@@ -330,10 +334,8 @@
         next_issue_(next_issue),
         start_req_(start_req) {}
   ~ClientRpcContextStreamingImpl() override {}
-  void Start(CompletionQueue* cq) override {
-    cq_ = cq;
-    stream_ = start_req_(stub_, &context_, cq, ClientRpcContext::tag(this));
-    next_state_ = State::STREAM_IDLE;
+  void Start(CompletionQueue* cq, const ClientConfig& config) override {
+    StartInternal(cq, config.messages_per_stream());
   }
   bool RunNextState(bool ok, HistogramEntry* entry) override {
     while (true) {
@@ -346,9 +348,9 @@
           }
           break;  // loop around, don't return
         case State::WAIT:
+          next_state_ = State::READY_TO_WRITE;
           alarm_.reset(
               new Alarm(cq_, next_issue_(), ClientRpcContext::tag(this)));
-          next_state_ = State::READY_TO_WRITE;
           return true;
         case State::READY_TO_WRITE:
           if (!ok) {
@@ -369,17 +371,32 @@
         case State::READ_DONE:
           entry->set_value((UsageTimer::Now() - start_) * 1e9);
           callback_(status_, &response_);
+          if ((messages_per_stream_ != 0) &&
+              (++messages_issued_ >= messages_per_stream_)) {
+            next_state_ = State::WRITES_DONE_DONE;
+            stream_->WritesDone(ClientRpcContext::tag(this));
+            return true;
+          }
           next_state_ = State::STREAM_IDLE;
           break;  // loop around
+        case State::WRITES_DONE_DONE:
+          next_state_ = State::FINISH_DONE;
+          stream_->Finish(&status_, ClientRpcContext::tag(this));
+          return true;
+        case State::FINISH_DONE:
+          next_state_ = State::INVALID;
+          return false;
+          break;
         default:
           GPR_ASSERT(false);
           return false;
       }
     }
   }
-  ClientRpcContext* StartNewClone() override {
-    return new ClientRpcContextStreamingImpl(stub_, req_, next_issue_,
-                                             start_req_, callback_);
+  void StartNewClone(CompletionQueue* cq) override {
+    auto* clone = new ClientRpcContextStreamingImpl(stub_, req_, next_issue_,
+                                                    start_req_, callback_);
+    clone->StartInternal(cq, messages_per_stream_);
   }
 
  private:
@@ -395,7 +412,9 @@
     WAIT,
     READY_TO_WRITE,
     WRITE_DONE,
-    READ_DONE
+    READ_DONE,
+    WRITES_DONE_DONE,
+    FINISH_DONE
   };
   State next_state_;
   std::function<void(grpc::Status, ResponseType*)> callback_;
@@ -408,6 +427,18 @@
   double start_;
   std::unique_ptr<grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>
       stream_;
+
+  // Allow a limit on number of messages in a stream
+  int messages_per_stream_;
+  int messages_issued_;
+
+  void StartInternal(CompletionQueue* cq, int messages_per_stream) {
+    cq_ = cq;
+    next_state_ = State::STREAM_IDLE;
+    stream_ = start_req_(stub_, &context_, cq, ClientRpcContext::tag(this));
+    messages_per_stream_ = messages_per_stream;
+    messages_issued_ = 0;
+  }
 };
 
 class AsyncStreamingClient final
@@ -459,13 +490,8 @@
         next_issue_(next_issue),
         start_req_(start_req) {}
   ~ClientRpcContextGenericStreamingImpl() override {}
-  void Start(CompletionQueue* cq) override {
-    cq_ = cq;
-    const grpc::string kMethodName(
-        "/grpc.testing.BenchmarkService/StreamingCall");
-    stream_ = start_req_(stub_, &context_, kMethodName, cq,
-                         ClientRpcContext::tag(this));
-    next_state_ = State::STREAM_IDLE;
+  void Start(CompletionQueue* cq, const ClientConfig& config) override {
+    StartInternal(cq, config.messages_per_stream());
   }
   bool RunNextState(bool ok, HistogramEntry* entry) override {
     while (true) {
@@ -478,9 +504,9 @@
           }
           break;  // loop around, don't return
         case State::WAIT:
+          next_state_ = State::READY_TO_WRITE;
           alarm_.reset(
               new Alarm(cq_, next_issue_(), ClientRpcContext::tag(this)));
-          next_state_ = State::READY_TO_WRITE;
           return true;
         case State::READY_TO_WRITE:
           if (!ok) {
@@ -501,17 +527,32 @@
         case State::READ_DONE:
           entry->set_value((UsageTimer::Now() - start_) * 1e9);
           callback_(status_, &response_);
+          if ((messages_per_stream_ != 0) &&
+              (++messages_issued_ >= messages_per_stream_)) {
+            next_state_ = State::WRITES_DONE_DONE;
+            stream_->WritesDone(ClientRpcContext::tag(this));
+            return true;
+          }
           next_state_ = State::STREAM_IDLE;
           break;  // loop around
+        case State::WRITES_DONE_DONE:
+          next_state_ = State::FINISH_DONE;
+          stream_->Finish(&status_, ClientRpcContext::tag(this));
+          return true;
+        case State::FINISH_DONE:
+          next_state_ = State::INVALID;
+          return false;
+          break;
         default:
           GPR_ASSERT(false);
           return false;
       }
     }
   }
-  ClientRpcContext* StartNewClone() override {
-    return new ClientRpcContextGenericStreamingImpl(stub_, req_, next_issue_,
-                                                    start_req_, callback_);
+  void StartNewClone(CompletionQueue* cq) override {
+    auto* clone = new ClientRpcContextGenericStreamingImpl(
+        stub_, req_, next_issue_, start_req_, callback_);
+    clone->StartInternal(cq, messages_per_stream_);
   }
 
  private:
@@ -527,7 +568,9 @@
     WAIT,
     READY_TO_WRITE,
     WRITE_DONE,
-    READ_DONE
+    READ_DONE,
+    WRITES_DONE_DONE,
+    FINISH_DONE
   };
   State next_state_;
   std::function<void(grpc::Status, ByteBuffer*)> callback_;
@@ -539,6 +582,21 @@
   grpc::Status status_;
   double start_;
   std::unique_ptr<grpc::GenericClientAsyncReaderWriter> stream_;
+
+  // Allow a limit on number of messages in a stream
+  int messages_per_stream_;
+  int messages_issued_;
+
+  void StartInternal(CompletionQueue* cq, int messages_per_stream) {
+    cq_ = cq;
+    const grpc::string kMethodName(
+        "/grpc.testing.BenchmarkService/StreamingCall");
+    next_state_ = State::STREAM_IDLE;
+    stream_ = start_req_(stub_, &context_, kMethodName, cq,
+                         ClientRpcContext::tag(this));
+    messages_per_stream_ = messages_per_stream;
+    messages_issued_ = 0;
+  }
 };
 
 static std::unique_ptr<grpc::GenericStub> GenericStubCreator(
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index a944c45..a020add 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -142,10 +142,13 @@
   SynchronousStreamingClient(const ClientConfig& config)
       : SynchronousClient(config),
         context_(num_threads_),
-        stream_(num_threads_) {
+        stream_(num_threads_),
+        messages_per_stream_(config.messages_per_stream()),
+        messages_issued_(num_threads_) {
     for (size_t thread_idx = 0; thread_idx < num_threads_; thread_idx++) {
       auto* stub = channels_[thread_idx % channels_.size()].get_stub();
       stream_[thread_idx] = stub->StreamingCall(&context_[thread_idx]);
+      messages_issued_[thread_idx] = 0;
     }
     StartThreads(num_threads_);
   }
@@ -173,11 +176,17 @@
         stream_[thread_idx]->Read(&responses_[thread_idx])) {
       entry->set_value((UsageTimer::Now() - start) * 1e9);
       // don't set the status since there isn't one yet
-      return true;
+      if ((messages_per_stream_ != 0) &&
+          (++messages_issued_[thread_idx] < messages_per_stream_)) {
+        return true;
+      } else {
+        // Fall through to the below resetting code after finish
+      }
     }
     stream_[thread_idx]->WritesDone();
     Status s = stream_[thread_idx]->Finish();
-    // don't set the value since the stream is failed and shouldn't be timed
+    // don't set the value since this is either a failure (shouldn't be timed)
+    // or a stream-end (already has been timed)
     entry->set_status(s.error_code());
     if (!s.ok()) {
       gpr_log(GPR_ERROR, "Stream %" PRIuPTR " received an error %s", thread_idx,
@@ -187,6 +196,7 @@
     context_[thread_idx].~ClientContext();
     new (&context_[thread_idx]) ClientContext();
     stream_[thread_idx] = stub->StreamingCall(&context_[thread_idx]);
+    messages_issued_[thread_idx] = 0;
     return true;
   }
 
@@ -197,6 +207,8 @@
   std::vector<
       std::unique_ptr<grpc::ClientReaderWriter<SimpleRequest, SimpleResponse>>>
       stream_;
+  const int messages_per_stream_;
+  std::vector<int> messages_issued_;
 };
 
 std::unique_ptr<Client> CreateSynchronousUnaryClient(
diff --git a/test/distrib/csharp/run_distrib_test.bat b/test/distrib/csharp/run_distrib_test.bat
index 6cf3811..cb5dd55 100644
--- a/test/distrib/csharp/run_distrib_test.bat
+++ b/test/distrib/csharp/run_distrib_test.bat
@@ -31,7 +31,7 @@
 cd /d %~dp0
 
 @rem extract input artifacts
-powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::ExtractToDirectory('../../../input_artifacts/csharp_nugets_dotnetcli.zip', 'TestNugetFeed');"
+powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::ExtractToDirectory('../../../input_artifacts/csharp_nugets_windows_dotnetcli.zip', 'TestNugetFeed');"
 
 update_version.sh auto
 
diff --git a/test/distrib/csharp/run_distrib_test.sh b/test/distrib/csharp/run_distrib_test.sh
index 0a77c1a..9de5ce0 100755
--- a/test/distrib/csharp/run_distrib_test.sh
+++ b/test/distrib/csharp/run_distrib_test.sh
@@ -32,7 +32,7 @@
 
 cd $(dirname $0)
 
-unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_dotnetcli.zip" -d TestNugetFeed
+unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_windows_dotnetcli.zip" -d TestNugetFeed
 
 ./update_version.sh auto
 
diff --git a/test/distrib/csharp/run_distrib_test_dotnetcli.sh b/test/distrib/csharp/run_distrib_test_dotnetcli.sh
index 493c504..cdfc91b 100755
--- a/test/distrib/csharp/run_distrib_test_dotnetcli.sh
+++ b/test/distrib/csharp/run_distrib_test_dotnetcli.sh
@@ -32,7 +32,7 @@
 
 cd $(dirname $0)
 
-unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_dotnetcli.zip" -d TestNugetFeed
+unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_windows_dotnetcli.zip" -d TestNugetFeed
 
 ./update_version.sh auto
 
diff --git a/tools/codegen/core/gen_nano_proto.sh b/tools/codegen/core/gen_nano_proto.sh
index 8600573..7bb9fc1 100755
--- a/tools/codegen/core/gen_nano_proto.sh
+++ b/tools/codegen/core/gen_nano_proto.sh
@@ -32,8 +32,8 @@
 # Example usage:
 #   tools/codegen/core/gen_nano_proto.sh \
 #     src/proto/grpc/lb/v1/load_balancer.proto \
-#     $PWD/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1 \
-#     src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1
+#     $PWD/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1 \
+#     src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1
 #
 # Exit statuses:
 # 1: Incorrect number of arguments
diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py
index 710e870..42005e3 100755
--- a/tools/distrib/check_copyright.py
+++ b/tools/distrib/check_copyright.py
@@ -104,8 +104,8 @@
   'examples/python/route_guide/route_guide_pb2.py',
   'examples/python/route_guide/route_guide_pb2_grpc.py',
 
-  'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
-  'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
+  'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
+  'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
   'src/cpp/server/health/health.pb.h',
   'src/cpp/server/health/health.pb.c',
 
diff --git a/tools/distrib/check_include_guards.py b/tools/distrib/check_include_guards.py
index 2831281..c7c2678 100755
--- a/tools/distrib/check_include_guards.py
+++ b/tools/distrib/check_include_guards.py
@@ -171,7 +171,7 @@
 args = argp.parse_args()
 
 KNOWN_BAD = set([
-    'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
+    'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
     'include/grpc++/ext/reflection.grpc.pb.h',
     'include/grpc++/ext/reflection.pb.h',
 ])
diff --git a/tools/distrib/check_nanopb_output.sh b/tools/distrib/check_nanopb_output.sh
index eb64e23..ba50282 100755
--- a/tools/distrib/check_nanopb_output.sh
+++ b/tools/distrib/check_nanopb_output.sh
@@ -58,7 +58,7 @@
 #
 # Checks for load_balancer.proto
 #
-readonly LOAD_BALANCER_GRPC_OUTPUT_PATH='src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1'
+readonly LOAD_BALANCER_GRPC_OUTPUT_PATH='src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1'
 # nanopb-compile the proto to a temp location
 ./tools/codegen/core/gen_nano_proto.sh \
   src/proto/grpc/lb/v1/load_balancer.proto \
@@ -66,7 +66,7 @@
   "$LOAD_BALANCER_GRPC_OUTPUT_PATH"
 
 # compare outputs to checked compiled code
-if ! diff -r $NANOPB_TMP_OUTPUT src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1; then
+if ! diff -r $NANOPB_TMP_OUTPUT src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1; then
   echo "Outputs differ: $NANOPB_TMP_OUTPUT vs $LOAD_BALANCER_GRPC_OUTPUT_PATH"
   exit 2
 fi
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
index c26c9a2..2a59628 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
@@ -99,8 +99,8 @@
 
 # Install dotnet SDK based on https://www.microsoft.com/net/core#debian
 RUN apt-get update && apt-get install -y curl libunwind8 gettext
-# dotnet-dev-1.0.0-preview2-003121
-RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=809130
+# dotnet-dev-1.0.0-preview2-003131
+RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
 RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
 # dotnet-dev-1.0.1
 RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
diff --git a/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile b/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile
index c26c9a2..2a59628 100644
--- a/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile
+++ b/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile
@@ -99,8 +99,8 @@
 
 # Install dotnet SDK based on https://www.microsoft.com/net/core#debian
 RUN apt-get update && apt-get install -y curl libunwind8 gettext
-# dotnet-dev-1.0.0-preview2-003121
-RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=809130
+# dotnet-dev-1.0.0-preview2-003131
+RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
 RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
 # dotnet-dev-1.0.1
 RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 6d171e3..209d544 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -923,8 +923,6 @@
 src/core/lib/channel/http_client_filter.h \
 src/core/lib/channel/http_server_filter.c \
 src/core/lib/channel/http_server_filter.h \
-src/core/lib/channel/max_age_filter.c \
-src/core/lib/channel/max_age_filter.h \
 src/core/lib/channel/message_size_filter.c \
 src/core/lib/channel/message_size_filter.h \
 src/core/lib/compression/algorithm_metadata.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index a934349..6903a0e 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -895,69 +895,71 @@
 src/core/ext/census/trace_string.h \
 src/core/ext/census/tracing.c \
 src/core/ext/census/tracing.h \
-src/core/ext/client_channel/README.md \
-src/core/ext/client_channel/channel_connectivity.c \
-src/core/ext/client_channel/client_channel.c \
-src/core/ext/client_channel/client_channel.h \
-src/core/ext/client_channel/client_channel_factory.c \
-src/core/ext/client_channel/client_channel_factory.h \
-src/core/ext/client_channel/client_channel_plugin.c \
-src/core/ext/client_channel/connector.c \
-src/core/ext/client_channel/connector.h \
-src/core/ext/client_channel/http_connect_handshaker.c \
-src/core/ext/client_channel/http_connect_handshaker.h \
-src/core/ext/client_channel/http_proxy.c \
-src/core/ext/client_channel/http_proxy.h \
-src/core/ext/client_channel/lb_policy.c \
-src/core/ext/client_channel/lb_policy.h \
-src/core/ext/client_channel/lb_policy_factory.c \
-src/core/ext/client_channel/lb_policy_factory.h \
-src/core/ext/client_channel/lb_policy_registry.c \
-src/core/ext/client_channel/lb_policy_registry.h \
-src/core/ext/client_channel/parse_address.c \
-src/core/ext/client_channel/parse_address.h \
-src/core/ext/client_channel/proxy_mapper.c \
-src/core/ext/client_channel/proxy_mapper.h \
-src/core/ext/client_channel/proxy_mapper_registry.c \
-src/core/ext/client_channel/proxy_mapper_registry.h \
-src/core/ext/client_channel/resolver.c \
-src/core/ext/client_channel/resolver.h \
-src/core/ext/client_channel/resolver_factory.c \
-src/core/ext/client_channel/resolver_factory.h \
-src/core/ext/client_channel/resolver_registry.c \
-src/core/ext/client_channel/resolver_registry.h \
-src/core/ext/client_channel/retry_throttle.c \
-src/core/ext/client_channel/retry_throttle.h \
-src/core/ext/client_channel/subchannel.c \
-src/core/ext/client_channel/subchannel.h \
-src/core/ext/client_channel/subchannel_index.c \
-src/core/ext/client_channel/subchannel_index.h \
-src/core/ext/client_channel/uri_parser.c \
-src/core/ext/client_channel/uri_parser.h \
-src/core/ext/lb_policy/grpclb/grpclb.c \
-src/core/ext/lb_policy/grpclb/grpclb.h \
-src/core/ext/lb_policy/grpclb/grpclb_channel.h \
-src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c \
-src/core/ext/lb_policy/grpclb/load_balancer_api.c \
-src/core/ext/lb_policy/grpclb/load_balancer_api.h \
-src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
-src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h \
-src/core/ext/lb_policy/pick_first/pick_first.c \
-src/core/ext/lb_policy/round_robin/round_robin.c \
-src/core/ext/load_reporting/load_reporting.c \
-src/core/ext/load_reporting/load_reporting.h \
-src/core/ext/load_reporting/load_reporting_filter.c \
-src/core/ext/load_reporting/load_reporting_filter.h \
-src/core/ext/resolver/README.md \
-src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c \
-src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h \
-src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
-src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c \
-src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h \
-src/core/ext/resolver/dns/native/README.md \
-src/core/ext/resolver/dns/native/dns_resolver.c \
-src/core/ext/resolver/sockaddr/README.md \
-src/core/ext/resolver/sockaddr/sockaddr_resolver.c \
+src/core/ext/filters/client_channel/README.md \
+src/core/ext/filters/client_channel/channel_connectivity.c \
+src/core/ext/filters/client_channel/client_channel.c \
+src/core/ext/filters/client_channel/client_channel.h \
+src/core/ext/filters/client_channel/client_channel_factory.c \
+src/core/ext/filters/client_channel/client_channel_factory.h \
+src/core/ext/filters/client_channel/client_channel_plugin.c \
+src/core/ext/filters/client_channel/connector.c \
+src/core/ext/filters/client_channel/connector.h \
+src/core/ext/filters/client_channel/http_connect_handshaker.c \
+src/core/ext/filters/client_channel/http_connect_handshaker.h \
+src/core/ext/filters/client_channel/http_proxy.c \
+src/core/ext/filters/client_channel/http_proxy.h \
+src/core/ext/filters/client_channel/lb_policy.c \
+src/core/ext/filters/client_channel/lb_policy.h \
+src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c \
+src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h \
+src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h \
+src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c \
+src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c \
+src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h \
+src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
+src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h \
+src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c \
+src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c \
+src/core/ext/filters/client_channel/lb_policy_factory.c \
+src/core/ext/filters/client_channel/lb_policy_factory.h \
+src/core/ext/filters/client_channel/lb_policy_registry.c \
+src/core/ext/filters/client_channel/lb_policy_registry.h \
+src/core/ext/filters/client_channel/parse_address.c \
+src/core/ext/filters/client_channel/parse_address.h \
+src/core/ext/filters/client_channel/proxy_mapper.c \
+src/core/ext/filters/client_channel/proxy_mapper.h \
+src/core/ext/filters/client_channel/proxy_mapper_registry.c \
+src/core/ext/filters/client_channel/proxy_mapper_registry.h \
+src/core/ext/filters/client_channel/resolver.c \
+src/core/ext/filters/client_channel/resolver.h \
+src/core/ext/filters/client_channel/resolver/README.md \
+src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c \
+src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h \
+src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
+src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c \
+src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h \
+src/core/ext/filters/client_channel/resolver/dns/native/README.md \
+src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c \
+src/core/ext/filters/client_channel/resolver/sockaddr/README.md \
+src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c \
+src/core/ext/filters/client_channel/resolver_factory.c \
+src/core/ext/filters/client_channel/resolver_factory.h \
+src/core/ext/filters/client_channel/resolver_registry.c \
+src/core/ext/filters/client_channel/resolver_registry.h \
+src/core/ext/filters/client_channel/retry_throttle.c \
+src/core/ext/filters/client_channel/retry_throttle.h \
+src/core/ext/filters/client_channel/subchannel.c \
+src/core/ext/filters/client_channel/subchannel.h \
+src/core/ext/filters/client_channel/subchannel_index.c \
+src/core/ext/filters/client_channel/subchannel_index.h \
+src/core/ext/filters/client_channel/uri_parser.c \
+src/core/ext/filters/client_channel/uri_parser.h \
+src/core/ext/filters/load_reporting/load_reporting.c \
+src/core/ext/filters/load_reporting/load_reporting.h \
+src/core/ext/filters/load_reporting/load_reporting_filter.c \
+src/core/ext/filters/load_reporting/load_reporting_filter.h \
+src/core/ext/filters/max_age/max_age_filter.c \
+src/core/ext/filters/max_age/max_age_filter.h \
 src/core/ext/transport/README.md \
 src/core/ext/transport/chttp2/README.md \
 src/core/ext/transport/chttp2/alpn/alpn.c \
@@ -1040,8 +1042,6 @@
 src/core/lib/channel/http_client_filter.h \
 src/core/lib/channel/http_server_filter.c \
 src/core/lib/channel/http_server_filter.h \
-src/core/lib/channel/max_age_filter.c \
-src/core/lib/channel/max_age_filter.h \
 src/core/lib/channel/message_size_filter.c \
 src/core/lib/channel/message_size_filter.h \
 src/core/lib/compression/algorithm_metadata.h \
diff --git a/tools/profiling/latency_profile/run_latency_profile.sh b/tools/jenkins/run_performance_profile_daily.sh
similarity index 86%
rename from tools/profiling/latency_profile/run_latency_profile.sh
rename to tools/jenkins/run_performance_profile_daily.sh
index 41423fc..f239fad 100755
--- a/tools/profiling/latency_profile/run_latency_profile.sh
+++ b/tools/jenkins/run_performance_profile_daily.sh
@@ -30,9 +30,7 @@
 
 set -ex
 
-cd $(dirname $0)/../../..
-
-CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
+cd $(dirname $0)/../..
 
 # try to use pypy for generating reports
 # each trace dumps 7-8gig of text to disk, and processing this into a report is
@@ -44,9 +42,4 @@
   PYTHON=python2.7
 fi
 
-make CONFIG=opt memory_profile_test memory_profile_client memory_profile_server
-bins/opt/memory_profile_test
-bq load microbenchmarks.memory memory_usage.csv
-
-$PYTHON tools/run_tests/run_microbenchmark.py --collect summary perf latency --bigquery_upload
-
+$PYTHON tools/run_tests/run_microbenchmark.py --collect summary perf latency
diff --git a/tools/profiling/latency_profile/run_latency_profile.sh b/tools/jenkins/run_performance_profile_hourly.sh
similarity index 78%
copy from tools/profiling/latency_profile/run_latency_profile.sh
copy to tools/jenkins/run_performance_profile_hourly.sh
index 41423fc..dfcc2bb 100755
--- a/tools/profiling/latency_profile/run_latency_profile.sh
+++ b/tools/jenkins/run_performance_profile_hourly.sh
@@ -30,23 +30,12 @@
 
 set -ex
 
-cd $(dirname $0)/../../..
+cd $(dirname $0)/../..
 
 CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
 
-# try to use pypy for generating reports
-# each trace dumps 7-8gig of text to disk, and processing this into a report is
-# heavyweight - so any speed boost is worthwhile
-# TODO(ctiller): consider rewriting report generation in C++ for performance
-if which pypy >/dev/null; then
-  PYTHON=pypy
-else
-  PYTHON=python2.7
-fi
-
-make CONFIG=opt memory_profile_test memory_profile_client memory_profile_server
+make CONFIG=opt memory_profile_test memory_profile_client memory_profile_server -j $CPUS
 bins/opt/memory_profile_test
 bq load microbenchmarks.memory memory_usage.csv
 
-$PYTHON tools/run_tests/run_microbenchmark.py --collect summary perf latency --bigquery_upload
-
+tools/run_tests/run_microbenchmark.py --collect summary --bigquery_upload
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index be1d876..11176d9 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -2566,6 +2566,27 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c++", 
+    "name": "bm_cq_multiple_threads", 
+    "src": [
+      "test/cpp/microbenchmarks/bm_cq_multiple_threads.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "benchmark", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_benchmark", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
     "name": "bm_error", 
     "src": [
       "test/cpp/microbenchmarks/bm_error.cc"
@@ -5576,6 +5597,7 @@
       "grpc_lb_policy_pick_first", 
       "grpc_lb_policy_round_robin", 
       "grpc_load_reporting", 
+      "grpc_max_age_filter", 
       "grpc_resolver_dns_ares", 
       "grpc_resolver_dns_native", 
       "grpc_resolver_sockaddr", 
@@ -5678,6 +5700,7 @@
       "grpc_lb_policy_pick_first", 
       "grpc_lb_policy_round_robin", 
       "grpc_load_reporting", 
+      "grpc_max_age_filter", 
       "grpc_resolver_dns_ares", 
       "grpc_resolver_dns_native", 
       "grpc_resolver_sockaddr", 
@@ -5991,11 +6014,15 @@
       "src/compiler/objective_c_generator_helpers.h", 
       "src/compiler/php_generator.h", 
       "src/compiler/php_generator_helpers.h", 
+      "src/compiler/protobuf_plugin.h", 
       "src/compiler/python_generator.h", 
+      "src/compiler/python_generator_helpers.h", 
+      "src/compiler/python_private_generator.h", 
       "src/compiler/ruby_generator.h", 
       "src/compiler/ruby_generator_helpers-inl.h", 
       "src/compiler/ruby_generator_map-inl.h", 
-      "src/compiler/ruby_generator_string-inl.h"
+      "src/compiler/ruby_generator_string-inl.h", 
+      "src/compiler/schema_interface.h"
     ], 
     "is_filegroup": false, 
     "language": "c++", 
@@ -6018,13 +6045,17 @@
       "src/compiler/php_generator.cc", 
       "src/compiler/php_generator.h", 
       "src/compiler/php_generator_helpers.h", 
+      "src/compiler/protobuf_plugin.h", 
       "src/compiler/python_generator.cc", 
       "src/compiler/python_generator.h", 
+      "src/compiler/python_generator_helpers.h", 
+      "src/compiler/python_private_generator.h", 
       "src/compiler/ruby_generator.cc", 
       "src/compiler/ruby_generator.h", 
       "src/compiler/ruby_generator_helpers-inl.h", 
       "src/compiler/ruby_generator_map-inl.h", 
-      "src/compiler/ruby_generator_string-inl.h"
+      "src/compiler/ruby_generator_string-inl.h", 
+      "src/compiler/schema_interface.h"
     ], 
     "third_party": false, 
     "type": "lib"
@@ -7119,6 +7150,7 @@
       "test/core/end2end/end2end_tests.h", 
       "test/core/end2end/tests/authority_not_supported.c", 
       "test/core/end2end/tests/bad_hostname.c", 
+      "test/core/end2end/tests/bad_ping.c", 
       "test/core/end2end/tests/binary_metadata.c", 
       "test/core/end2end/tests/call_creds.c", 
       "test/core/end2end/tests/cancel_after_accept.c", 
@@ -7194,6 +7226,7 @@
       "test/core/end2end/end2end_tests.h", 
       "test/core/end2end/tests/authority_not_supported.c", 
       "test/core/end2end/tests/bad_hostname.c", 
+      "test/core/end2end/tests/bad_ping.c", 
       "test/core/end2end/tests/binary_metadata.c", 
       "test/core/end2end/tests/cancel_after_accept.c", 
       "test/core/end2end/tests/cancel_after_client_done.c", 
@@ -7514,7 +7547,6 @@
       "src/core/lib/channel/handshaker_registry.h", 
       "src/core/lib/channel/http_client_filter.h", 
       "src/core/lib/channel/http_server_filter.h", 
-      "src/core/lib/channel/max_age_filter.h", 
       "src/core/lib/channel/message_size_filter.h", 
       "src/core/lib/compression/algorithm_metadata.h", 
       "src/core/lib/compression/message_compress.h", 
@@ -7651,8 +7683,6 @@
       "src/core/lib/channel/http_client_filter.h", 
       "src/core/lib/channel/http_server_filter.c", 
       "src/core/lib/channel/http_server_filter.h", 
-      "src/core/lib/channel/max_age_filter.c", 
-      "src/core/lib/channel/max_age_filter.h", 
       "src/core/lib/channel/message_size_filter.c", 
       "src/core/lib/channel/message_size_filter.h", 
       "src/core/lib/compression/algorithm_metadata.h", 
@@ -7874,67 +7904,67 @@
       "grpc_base"
     ], 
     "headers": [
-      "src/core/ext/client_channel/client_channel.h", 
-      "src/core/ext/client_channel/client_channel_factory.h", 
-      "src/core/ext/client_channel/connector.h", 
-      "src/core/ext/client_channel/http_connect_handshaker.h", 
-      "src/core/ext/client_channel/http_proxy.h", 
-      "src/core/ext/client_channel/lb_policy.h", 
-      "src/core/ext/client_channel/lb_policy_factory.h", 
-      "src/core/ext/client_channel/lb_policy_registry.h", 
-      "src/core/ext/client_channel/parse_address.h", 
-      "src/core/ext/client_channel/proxy_mapper.h", 
-      "src/core/ext/client_channel/proxy_mapper_registry.h", 
-      "src/core/ext/client_channel/resolver.h", 
-      "src/core/ext/client_channel/resolver_factory.h", 
-      "src/core/ext/client_channel/resolver_registry.h", 
-      "src/core/ext/client_channel/retry_throttle.h", 
-      "src/core/ext/client_channel/subchannel.h", 
-      "src/core/ext/client_channel/subchannel_index.h", 
-      "src/core/ext/client_channel/uri_parser.h"
+      "src/core/ext/filters/client_channel/client_channel.h", 
+      "src/core/ext/filters/client_channel/client_channel_factory.h", 
+      "src/core/ext/filters/client_channel/connector.h", 
+      "src/core/ext/filters/client_channel/http_connect_handshaker.h", 
+      "src/core/ext/filters/client_channel/http_proxy.h", 
+      "src/core/ext/filters/client_channel/lb_policy.h", 
+      "src/core/ext/filters/client_channel/lb_policy_factory.h", 
+      "src/core/ext/filters/client_channel/lb_policy_registry.h", 
+      "src/core/ext/filters/client_channel/parse_address.h", 
+      "src/core/ext/filters/client_channel/proxy_mapper.h", 
+      "src/core/ext/filters/client_channel/proxy_mapper_registry.h", 
+      "src/core/ext/filters/client_channel/resolver.h", 
+      "src/core/ext/filters/client_channel/resolver_factory.h", 
+      "src/core/ext/filters/client_channel/resolver_registry.h", 
+      "src/core/ext/filters/client_channel/retry_throttle.h", 
+      "src/core/ext/filters/client_channel/subchannel.h", 
+      "src/core/ext/filters/client_channel/subchannel_index.h", 
+      "src/core/ext/filters/client_channel/uri_parser.h"
     ], 
     "is_filegroup": true, 
     "language": "c", 
     "name": "grpc_client_channel", 
     "src": [
-      "src/core/ext/client_channel/channel_connectivity.c", 
-      "src/core/ext/client_channel/client_channel.c", 
-      "src/core/ext/client_channel/client_channel.h", 
-      "src/core/ext/client_channel/client_channel_factory.c", 
-      "src/core/ext/client_channel/client_channel_factory.h", 
-      "src/core/ext/client_channel/client_channel_plugin.c", 
-      "src/core/ext/client_channel/connector.c", 
-      "src/core/ext/client_channel/connector.h", 
-      "src/core/ext/client_channel/http_connect_handshaker.c", 
-      "src/core/ext/client_channel/http_connect_handshaker.h", 
-      "src/core/ext/client_channel/http_proxy.c", 
-      "src/core/ext/client_channel/http_proxy.h", 
-      "src/core/ext/client_channel/lb_policy.c", 
-      "src/core/ext/client_channel/lb_policy.h", 
-      "src/core/ext/client_channel/lb_policy_factory.c", 
-      "src/core/ext/client_channel/lb_policy_factory.h", 
-      "src/core/ext/client_channel/lb_policy_registry.c", 
-      "src/core/ext/client_channel/lb_policy_registry.h", 
-      "src/core/ext/client_channel/parse_address.c", 
-      "src/core/ext/client_channel/parse_address.h", 
-      "src/core/ext/client_channel/proxy_mapper.c", 
-      "src/core/ext/client_channel/proxy_mapper.h", 
-      "src/core/ext/client_channel/proxy_mapper_registry.c", 
-      "src/core/ext/client_channel/proxy_mapper_registry.h", 
-      "src/core/ext/client_channel/resolver.c", 
-      "src/core/ext/client_channel/resolver.h", 
-      "src/core/ext/client_channel/resolver_factory.c", 
-      "src/core/ext/client_channel/resolver_factory.h", 
-      "src/core/ext/client_channel/resolver_registry.c", 
-      "src/core/ext/client_channel/resolver_registry.h", 
-      "src/core/ext/client_channel/retry_throttle.c", 
-      "src/core/ext/client_channel/retry_throttle.h", 
-      "src/core/ext/client_channel/subchannel.c", 
-      "src/core/ext/client_channel/subchannel.h", 
-      "src/core/ext/client_channel/subchannel_index.c", 
-      "src/core/ext/client_channel/subchannel_index.h", 
-      "src/core/ext/client_channel/uri_parser.c", 
-      "src/core/ext/client_channel/uri_parser.h"
+      "src/core/ext/filters/client_channel/channel_connectivity.c", 
+      "src/core/ext/filters/client_channel/client_channel.c", 
+      "src/core/ext/filters/client_channel/client_channel.h", 
+      "src/core/ext/filters/client_channel/client_channel_factory.c", 
+      "src/core/ext/filters/client_channel/client_channel_factory.h", 
+      "src/core/ext/filters/client_channel/client_channel_plugin.c", 
+      "src/core/ext/filters/client_channel/connector.c", 
+      "src/core/ext/filters/client_channel/connector.h", 
+      "src/core/ext/filters/client_channel/http_connect_handshaker.c", 
+      "src/core/ext/filters/client_channel/http_connect_handshaker.h", 
+      "src/core/ext/filters/client_channel/http_proxy.c", 
+      "src/core/ext/filters/client_channel/http_proxy.h", 
+      "src/core/ext/filters/client_channel/lb_policy.c", 
+      "src/core/ext/filters/client_channel/lb_policy.h", 
+      "src/core/ext/filters/client_channel/lb_policy_factory.c", 
+      "src/core/ext/filters/client_channel/lb_policy_factory.h", 
+      "src/core/ext/filters/client_channel/lb_policy_registry.c", 
+      "src/core/ext/filters/client_channel/lb_policy_registry.h", 
+      "src/core/ext/filters/client_channel/parse_address.c", 
+      "src/core/ext/filters/client_channel/parse_address.h", 
+      "src/core/ext/filters/client_channel/proxy_mapper.c", 
+      "src/core/ext/filters/client_channel/proxy_mapper.h", 
+      "src/core/ext/filters/client_channel/proxy_mapper_registry.c", 
+      "src/core/ext/filters/client_channel/proxy_mapper_registry.h", 
+      "src/core/ext/filters/client_channel/resolver.c", 
+      "src/core/ext/filters/client_channel/resolver.h", 
+      "src/core/ext/filters/client_channel/resolver_factory.c", 
+      "src/core/ext/filters/client_channel/resolver_factory.h", 
+      "src/core/ext/filters/client_channel/resolver_registry.c", 
+      "src/core/ext/filters/client_channel/resolver_registry.h", 
+      "src/core/ext/filters/client_channel/retry_throttle.c", 
+      "src/core/ext/filters/client_channel/retry_throttle.h", 
+      "src/core/ext/filters/client_channel/subchannel.c", 
+      "src/core/ext/filters/client_channel/subchannel.h", 
+      "src/core/ext/filters/client_channel/subchannel_index.c", 
+      "src/core/ext/filters/client_channel/subchannel_index.h", 
+      "src/core/ext/filters/client_channel/uri_parser.c", 
+      "src/core/ext/filters/client_channel/uri_parser.h"
     ], 
     "third_party": false, 
     "type": "filegroup"
@@ -7977,23 +8007,23 @@
       "nanopb"
     ], 
     "headers": [
-      "src/core/ext/lb_policy/grpclb/grpclb.h", 
-      "src/core/ext/lb_policy/grpclb/grpclb_channel.h", 
-      "src/core/ext/lb_policy/grpclb/load_balancer_api.h", 
-      "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
     ], 
     "is_filegroup": true, 
     "language": "c", 
     "name": "grpc_lb_policy_grpclb", 
     "src": [
-      "src/core/ext/lb_policy/grpclb/grpclb.c", 
-      "src/core/ext/lb_policy/grpclb/grpclb.h", 
-      "src/core/ext/lb_policy/grpclb/grpclb_channel.c", 
-      "src/core/ext/lb_policy/grpclb/grpclb_channel.h", 
-      "src/core/ext/lb_policy/grpclb/load_balancer_api.c", 
-      "src/core/ext/lb_policy/grpclb/load_balancer_api.h", 
-      "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c", 
-      "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.c", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
     ], 
     "third_party": false, 
     "type": "filegroup"
@@ -8007,23 +8037,23 @@
       "nanopb"
     ], 
     "headers": [
-      "src/core/ext/lb_policy/grpclb/grpclb.h", 
-      "src/core/ext/lb_policy/grpclb/grpclb_channel.h", 
-      "src/core/ext/lb_policy/grpclb/load_balancer_api.h", 
-      "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
     ], 
     "is_filegroup": true, 
     "language": "c", 
     "name": "grpc_lb_policy_grpclb_secure", 
     "src": [
-      "src/core/ext/lb_policy/grpclb/grpclb.c", 
-      "src/core/ext/lb_policy/grpclb/grpclb.h", 
-      "src/core/ext/lb_policy/grpclb/grpclb_channel.h", 
-      "src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c", 
-      "src/core/ext/lb_policy/grpclb/load_balancer_api.c", 
-      "src/core/ext/lb_policy/grpclb/load_balancer_api.h", 
-      "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c", 
-      "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c", 
+      "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
     ], 
     "third_party": false, 
     "type": "filegroup"
@@ -8039,7 +8069,7 @@
     "language": "c", 
     "name": "grpc_lb_policy_pick_first", 
     "src": [
-      "src/core/ext/lb_policy/pick_first/pick_first.c"
+      "src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c"
     ], 
     "third_party": false, 
     "type": "filegroup"
@@ -8055,7 +8085,7 @@
     "language": "c", 
     "name": "grpc_lb_policy_round_robin", 
     "src": [
-      "src/core/ext/lb_policy/round_robin/round_robin.c"
+      "src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c"
     ], 
     "third_party": false, 
     "type": "filegroup"
@@ -8066,17 +8096,35 @@
       "grpc_base"
     ], 
     "headers": [
-      "src/core/ext/load_reporting/load_reporting.h", 
-      "src/core/ext/load_reporting/load_reporting_filter.h"
+      "src/core/ext/filters/load_reporting/load_reporting.h", 
+      "src/core/ext/filters/load_reporting/load_reporting_filter.h"
     ], 
     "is_filegroup": true, 
     "language": "c", 
     "name": "grpc_load_reporting", 
     "src": [
-      "src/core/ext/load_reporting/load_reporting.c", 
-      "src/core/ext/load_reporting/load_reporting.h", 
-      "src/core/ext/load_reporting/load_reporting_filter.c", 
-      "src/core/ext/load_reporting/load_reporting_filter.h"
+      "src/core/ext/filters/load_reporting/load_reporting.c", 
+      "src/core/ext/filters/load_reporting/load_reporting.h", 
+      "src/core/ext/filters/load_reporting/load_reporting_filter.c", 
+      "src/core/ext/filters/load_reporting/load_reporting_filter.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc_base"
+    ], 
+    "headers": [
+      "src/core/ext/filters/max_age/max_age_filter.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "grpc_max_age_filter", 
+    "src": [
+      "src/core/ext/filters/max_age/max_age_filter.c", 
+      "src/core/ext/filters/max_age/max_age_filter.h"
     ], 
     "third_party": false, 
     "type": "filegroup"
@@ -8088,18 +8136,18 @@
       "grpc_client_channel"
     ], 
     "headers": [
-      "src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h", 
-      "src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h"
+      "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h", 
+      "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
     ], 
     "is_filegroup": true, 
     "language": "c", 
     "name": "grpc_resolver_dns_ares", 
     "src": [
-      "src/core/ext/resolver/dns/c_ares/dns_resolver_ares.c", 
-      "src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver.h", 
-      "src/core/ext/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c", 
-      "src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.c", 
-      "src/core/ext/resolver/dns/c_ares/grpc_ares_wrapper.h"
+      "src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c", 
+      "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h", 
+      "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c", 
+      "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c", 
+      "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
     ], 
     "third_party": false, 
     "type": "filegroup"
@@ -8115,7 +8163,7 @@
     "language": "c", 
     "name": "grpc_resolver_dns_native", 
     "src": [
-      "src/core/ext/resolver/dns/native/dns_resolver.c"
+      "src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c"
     ], 
     "third_party": false, 
     "type": "filegroup"
@@ -8131,7 +8179,7 @@
     "language": "c", 
     "name": "grpc_resolver_sockaddr", 
     "src": [
-      "src/core/ext/resolver/sockaddr/sockaddr_resolver.c"
+      "src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c"
     ], 
     "third_party": false, 
     "type": "filegroup"
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 6013612..12d48f2 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -2752,6 +2752,28 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c++", 
+    "name": "bm_cq_multiple_threads", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "--benchmark_min_time=0"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
     "name": "bm_error", 
     "platforms": [
       "linux", 
@@ -5727,6 +5749,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -6927,6 +6972,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -8125,6 +8193,28 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -10333,6 +10423,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -11525,6 +11638,25 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -12521,6 +12653,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -13677,6 +13832,30 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -14923,6 +15102,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -16125,6 +16327,30 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -21709,6 +21935,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -22909,6 +23158,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_cert_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -25141,6 +25413,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -26314,6 +26609,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -27491,6 +27809,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -29703,6 +30044,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -30872,6 +31236,25 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -31849,6 +32232,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -32982,6 +33388,30 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -34204,6 +34634,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -39621,6 +40074,29 @@
   }, 
   {
     "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "binary_metadata"
     ], 
     "ci_platforms": [
@@ -40776,6 +41252,56 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_1mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_1mps_secure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_10mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_10mps_secure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_1channel_1MBmsg_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -40930,6 +41456,31 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_secure_1mb\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_secure_1mb", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_unary_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -41080,6 +41631,56 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_1mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 16, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1024, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_1mps_secure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_10mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 16, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1024, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_10mps_secure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -41130,6 +41731,56 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_1mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_1mps_secure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_10mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_10mps_secure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -41180,6 +41831,56 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_1mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_1mps_insecure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_10mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_10mps_insecure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_1channel_1MBmsg_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -41334,6 +42035,31 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_insecure_1mb\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_insecure_1mb", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_unary_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": null, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -41484,6 +42210,56 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_1mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 16, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1024, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_1mps_insecure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_10mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 16, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1024, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_10mps_insecure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -41534,6 +42310,56 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_1mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_1mps_insecure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_10mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_10mps_insecure", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -41608,6 +42434,80 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_1mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_1mps_secure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_10mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_10mps_secure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_1channel_1MBmsg_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -41834,6 +42734,43 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_secure_1mb\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_secure_1mb_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_unary_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -42056,6 +42993,80 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_1mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_1mps_secure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_10mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_10mps_secure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -42130,6 +43141,80 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_1mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_1mps_secure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_10mps_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_10mps_secure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -42204,6 +43289,80 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_1mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_1mps_insecure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_unconstrained_10mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_generic_async_streaming_qps_unconstrained_10mps_insecure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_qps_1channel_1MBmsg_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -42430,6 +43589,43 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_ping_pong_insecure_1mb\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_ping_pong_insecure_1mb_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_unary_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": null, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -42652,6 +43848,80 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_1mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_1mps_insecure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_sync_streaming_qps_unconstrained_10mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"SYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"SYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 64, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_sync_streaming_qps_unconstrained_10mps_insecure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_ping_pong_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -42725,6 +43995,80 @@
   }, 
   {
     "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_1mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 1, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_1mps_insecure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_qps_unconstrained_10mps_insecure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 0, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 64, \"async_client_threads\": 0, \"messages_per_stream\": 10, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_qps_unconstrained_10mps_insecure_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/00.bin"
     ], 
     "ci_platforms": [
@@ -83665,6 +85009,29 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5242554383597568"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-5834320218423296"
     ], 
     "ci_platforms": [
@@ -83711,6 +85078,29 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6499902139924480"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6520142139752448"
     ], 
     "ci_platforms": [
@@ -83734,6 +85124,29 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6699208922890240"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-6723650944237568"
     ], 
     "ci_platforms": [
@@ -149376,6 +150789,29 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-6312731374256128"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/crash-0f4b135c0242669ce425d2662168e9440f8a628d"
     ], 
     "ci_platforms": [
diff --git a/tools/run_tests/helper_scripts/build_node.sh b/tools/run_tests/helper_scripts/build_node.sh
index df3acda..2c4cf02 100755
--- a/tools/run_tests/helper_scripts/build_node.sh
+++ b/tools/run_tests/helper_scripts/build_node.sh
@@ -41,7 +41,8 @@
 cd $(dirname $0)/../../..
 
 case "$CONFIG" in
-  'dbg') config_flag='--debug' ;;
+  'dbg') config_flags='--debug' ;;
+  'gcov') config_flags="--debug --grpc_gcov=true" ;;
   *) config_flag='--release' ;;
 esac
 
diff --git a/tools/run_tests/helper_scripts/pre_build_csharp.bat b/tools/run_tests/helper_scripts/pre_build_csharp.bat
index 99df1c6..bee430a 100644
--- a/tools/run_tests/helper_scripts/pre_build_csharp.bat
+++ b/tools/run_tests/helper_scripts/pre_build_csharp.bat
@@ -43,7 +43,7 @@
 mkdir %ARCHITECTURE%
 cd %ARCHITECTURE%
 @rem TODO(jtattermusch): Stop hardcoding path to yasm once Jenkins workers can locate yasm correctly
-cmake -G "Visual Studio 14 2015" -A %ARCHITECTURE% -DgRPC_BUILD_TESTS=OFF -DCMAKE_ASM_NASM_COMPILER="C:/Program Files (x86)/yasm/yasm.exe" ../../.. || goto :error
+cmake -G "Visual Studio 14 2015" -A %ARCHITECTURE% -DgRPC_BUILD_TESTS=OFF -DgRPC_MSVC_STATIC_RUNTIME=ON -DCMAKE_ASM_NASM_COMPILER="C:/Program Files (x86)/yasm/yasm.exe" ../../.. || goto :error
 cd ..\..\..
 
 @rem Location of nuget.exe
diff --git a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
index d7da636..92d6975 100755
--- a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
+++ b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
@@ -38,4 +38,5 @@
 ruby src/ruby/end2end/channel_state_driver.rb || EXIT_CODE=1
 ruby src/ruby/end2end/channel_closing_driver.rb || EXIT_CODE=1
 ruby src/ruby/end2end/sig_int_during_channel_watch_driver.rb || EXIT_CODE=1
+ruby src/ruby/end2end/killed_client_thread_driver.rb || EXIT_CODE=1
 exit $EXIT_CODE
diff --git a/tools/run_tests/performance/build_performance.sh b/tools/run_tests/performance/build_performance.sh
index 5f8749d..3f7c9fe 100755
--- a/tools/run_tests/performance/build_performance.sh
+++ b/tools/run_tests/performance/build_performance.sh
@@ -61,6 +61,9 @@
   "csharp")
     python tools/run_tests/run_tests.py -l $language -c $CONFIG --build_only -j 8 --compiler coreclr
     ;;
+  "node")
+    python tools/run_tests/run_tests.py -l $language -c $CONFIG --build_only -j 8 --iomgr_platform=uv
+    ;;
   *)
     python tools/run_tests/run_tests.py -l $language -c $CONFIG --build_only -j 8
     ;;
diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py
index 7169c47..dca3fba 100644
--- a/tools/run_tests/performance/scenario_config.py
+++ b/tools/run_tests/performance/scenario_config.py
@@ -112,6 +112,7 @@
                         channels=None,
                         outstanding=None,
                         resource_quota_size=None,
+                        messages_per_stream=None,
                         excluded_poll_engines=[]):
   """Creates a basic ping pong scenario."""
   scenario = {
@@ -165,6 +166,8 @@
     scenario['client_config']['client_channels'] = 1
     scenario['client_config']['async_client_threads'] = 1
 
+  if messages_per_stream:
+    scenario['client_config']['messages_per_stream'] = messages_per_stream
   if client_language:
     # the CLIENT_LANGUAGE field is recognized by run_performance_tests.py
     scenario['CLIENT_LANGUAGE'] = client_language
@@ -214,6 +217,26 @@
           secure=secure,
           categories=smoketest_categories+[SCALABLE])
 
+      for mps in geometric_progression(1, 20, 10):
+        yield _ping_pong_scenario(
+            'cpp_generic_async_streaming_qps_unconstrained_%smps_%s' % (mps, secstr),
+            rpc_type='STREAMING',
+            client_type='ASYNC_CLIENT',
+            server_type='ASYNC_GENERIC_SERVER',
+            unconstrained_client='async', use_generic_payload=True,
+            secure=secure, messages_per_stream=mps,
+            categories=smoketest_categories+[SCALABLE])
+
+      for mps in geometric_progression(1, 200, math.sqrt(10)):
+        yield _ping_pong_scenario(
+            'cpp_generic_async_streaming_qps_unconstrained_%smps_%s' % (mps, secstr),
+            rpc_type='STREAMING',
+            client_type='ASYNC_CLIENT',
+            server_type='ASYNC_GENERIC_SERVER',
+            unconstrained_client='async', use_generic_payload=True,
+            secure=secure, messages_per_stream=mps,
+            categories=[SWEEP])
+
       yield _ping_pong_scenario(
           'cpp_generic_async_streaming_qps_1channel_1MBmsg_%s' % secstr,
           rpc_type='STREAMING',
@@ -280,6 +303,13 @@
           categories=smoketest_categories+[SCALABLE],
           excluded_poll_engines = ['poll-cv'])
 
+      yield _ping_pong_scenario(
+        'cpp_protobuf_async_unary_ping_pong_%s_1mb' % secstr, rpc_type='UNARY',
+        client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
+        req_size=1024*1024, resp_size=1024*1024,
+        secure=secure,
+        categories=smoketest_categories)
+
       for rpc_type in ['unary', 'streaming']:
         for synchronicity in ['sync', 'async']:
           yield _ping_pong_scenario(
@@ -324,6 +354,27 @@
           #     categories=smoketest_categories+[SCALABLE],
           #     resource_quota_size=500*1024)
 
+          if rpc_type == 'streaming':
+            for mps in geometric_progression(1, 20, 10):
+              yield _ping_pong_scenario(
+                  'cpp_protobuf_%s_%s_qps_unconstrained_%smps_%s' % (synchronicity, rpc_type, mps, secstr),
+                  rpc_type=rpc_type.upper(),
+                  client_type='%s_CLIENT' % synchronicity.upper(),
+                  server_type='%s_SERVER' % synchronicity.upper(),
+                  unconstrained_client=synchronicity,
+                  secure=secure, messages_per_stream=mps,
+                  categories=smoketest_categories+[SCALABLE])
+
+            for mps in geometric_progression(1, 200, math.sqrt(10)):
+              yield _ping_pong_scenario(
+                  'cpp_protobuf_%s_%s_qps_unconstrained_%smps_%s' % (synchronicity, rpc_type, mps, secstr),
+                  rpc_type=rpc_type.upper(),
+                  client_type='%s_CLIENT' % synchronicity.upper(),
+                  server_type='%s_SERVER' % synchronicity.upper(),
+                  unconstrained_client=synchronicity,
+                  secure=secure, messages_per_stream=mps,
+                  categories=[SWEEP])
+
           for channels in geometric_progression(1, 20000, math.sqrt(10)):
             for outstanding in geometric_progression(1, 200000, math.sqrt(10)):
                 if synchronicity == 'sync' and outstanding > 1200: continue
@@ -412,6 +463,12 @@
         unconstrained_client='async', client_language='c++',
         categories=[SCALABLE])
 
+    yield _ping_pong_scenario(
+        'csharp_protobuf_async_unary_ping_pong_1mb', rpc_type='UNARY',
+        client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
+        req_size=1024*1024, resp_size=1024*1024,
+        categories=[SMOKETEST])
+
 
   def __str__(self):
     return 'csharp'
@@ -449,9 +506,15 @@
 
     yield _ping_pong_scenario(
         'cpp_to_node_unary_ping_pong', rpc_type='UNARY',
-        client_type='ASYNC_CLIENT', server_type='async_server',
+        client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
         client_language='c++')
 
+    yield _ping_pong_scenario(
+        'node_protobuf_async_unary_ping_pong_1mb', rpc_type='UNARY',
+        client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
+        req_size=1024*1024, resp_size=1024*1024,
+        categories=[SMOKETEST])
+
     # TODO(murgatroid99): fix bugs with this scenario and re-enable it
     # yield _ping_pong_scenario(
     #     'node_protobuf_async_unary_qps_unconstrained', rpc_type='UNARY',
@@ -532,6 +595,12 @@
         client_type='SYNC_CLIENT', server_type='ASYNC_SERVER',
         server_language='c++', async_server_threads=1)
 
+    yield _ping_pong_scenario(
+        'python_protobuf_sync_unary_ping_pong_1mb', rpc_type='UNARY',
+        client_type='SYNC_CLIENT', server_type='ASYNC_SERVER',
+        req_size=1024*1024, resp_size=1024*1024,
+        categories=[SMOKETEST])
+
   def __str__(self):
     return 'python'
 
@@ -578,6 +647,12 @@
         client_type='SYNC_CLIENT', server_type='SYNC_SERVER',
         server_language='c++', async_server_threads=1)
 
+    yield _ping_pong_scenario(
+        'ruby_protobuf_async_unary_ping_pong_1mb', rpc_type='UNARY',
+        client_type='SYNC_CLIENT', server_type='SYNC_SERVER',
+        req_size=1024*1024, resp_size=1024*1024,
+        categories=[SMOKETEST])
+
   def __str__(self):
     return 'ruby'
 
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index a2b3e56..caa22a0 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -389,7 +389,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
@@ -598,8 +597,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index 57d4db2..6fc1c96 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -157,9 +157,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -902,9 +899,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index f0774aa..6748181 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -383,7 +383,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
@@ -582,8 +581,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index 2dd3d89..2b9a5b1 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -142,9 +142,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -869,9 +866,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index ada8f1a..948af2f 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -312,7 +312,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
@@ -455,37 +454,37 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security_interface.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\retry_throttle.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel_index.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\uri_parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_common.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_ev_driver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_wrapper.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\aggregation.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\base_resources.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_interface.h" />
@@ -502,6 +501,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_status.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_string.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
@@ -528,8 +528,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
@@ -858,45 +856,45 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\secure\secure_channel_create.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\channel_connectivity.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\channel_connectivity.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_plugin.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_plugin.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\retry_throttle.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel_index.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\uri_parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.c">
     </ClCompile>
@@ -908,13 +906,13 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb_channel_secure.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel_secure.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
     </ClCompile>
@@ -922,23 +920,23 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\pick_first\pick_first.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\pick_first\pick_first.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\round_robin\round_robin.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\round_robin\round_robin.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\dns_resolver_ares.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_wrapper.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\native\dns_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\sockaddr\sockaddr_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\sockaddr\sockaddr_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
     </ClCompile>
@@ -968,6 +966,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_plugin_registry.c">
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 0246845..d43b0e3 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -37,9 +37,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -532,65 +529,65 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\secure\secure_channel_create.c">
       <Filter>src\core\ext\transport\chttp2\client\secure</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\channel_connectivity.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\channel_connectivity.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_plugin.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_plugin.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_factory.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_registry.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_registry.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\retry_throttle.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel_index.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\uri_parser.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.c">
       <Filter>src\core\ext\transport\chttp2\client</Filter>
@@ -607,17 +604,17 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
       <Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb_channel_secure.c">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel_secure.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
-      <Filter>src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
       <Filter>third_party\nanopb</Filter>
@@ -628,32 +625,32 @@
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.c">
       <Filter>third_party\nanopb</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\pick_first\pick_first.c">
-      <Filter>src\core\ext\lb_policy\pick_first</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\pick_first\pick_first.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\pick_first</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\round_robin\round_robin.c">
-      <Filter>src\core\ext\lb_policy\round_robin</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\round_robin\round_robin.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\round_robin</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\dns_resolver_ares.c">
-      <Filter>src\core\ext\resolver\dns\c_ares</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
-      <Filter>src\core\ext\resolver\dns\c_ares</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_wrapper.c">
-      <Filter>src\core\ext\resolver\dns\c_ares</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\native\dns_resolver.c">
-      <Filter>src\core\ext\resolver\dns\native</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\native</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\sockaddr\sockaddr_resolver.c">
-      <Filter>src\core\ext\resolver\sockaddr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\sockaddr\sockaddr_resolver.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\sockaddr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.c">
-      <Filter>src\core\ext\load_reporting</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.c">
+      <Filter>src\core\ext\filters\load_reporting</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.c">
-      <Filter>src\core\ext\load_reporting</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.c">
+      <Filter>src\core\ext\filters\load_reporting</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
       <Filter>src\core\ext\census</Filter>
@@ -697,6 +694,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
       <Filter>src\core\ext\census</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
+      <Filter>src\core\ext\filters\max_age</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_plugin_registry.c">
       <Filter>src\core\plugin_registry</Filter>
     </ClCompile>
@@ -833,9 +833,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
@@ -1262,74 +1259,74 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h">
       <Filter>src\core\ext\transport\chttp2\server</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_factory.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_registry.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_registry.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\retry_throttle.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel_index.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\uri_parser.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h">
       <Filter>src\core\ext\transport\chttp2\client</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.h">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb_channel.h">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.h">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.h">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h">
-      <Filter>src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h">
       <Filter>third_party\nanopb</Filter>
@@ -1343,17 +1340,17 @@
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.h">
       <Filter>third_party\nanopb</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_ev_driver.h">
-      <Filter>src\core\ext\resolver\dns\c_ares</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_wrapper.h">
-      <Filter>src\core\ext\resolver\dns\c_ares</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.h">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.h">
-      <Filter>src\core\ext\load_reporting</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.h">
+      <Filter>src\core\ext\filters\load_reporting</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.h">
-      <Filter>src\core\ext\load_reporting</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.h">
+      <Filter>src\core\ext\filters\load_reporting</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\aggregation.h">
       <Filter>src\core\ext\census</Filter>
@@ -1403,6 +1400,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h">
+      <Filter>src\core\ext\filters\max_age</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
@@ -1433,50 +1433,56 @@
     <Filter Include="src\core\ext\census\gen">
       <UniqueIdentifier>{4a14dd37-5868-c656-7333-fa80574cbb07}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\client_channel">
-      <UniqueIdentifier>{36eee53a-cd19-738a-c387-20c44a2bfd07}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters">
+      <UniqueIdentifier>{a7cd279d-e0ec-32d3-4cbe-778aba4a0000}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy">
-      <UniqueIdentifier>{030f00ff-6c54-76c8-12df-37e3008335d1}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel">
+      <UniqueIdentifier>{d38c43fd-50e4-fba5-59c5-0d4817159aad}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\grpclb">
-      <UniqueIdentifier>{fe41339e-53fb-39b3-7457-7a0fbb238dbe}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy">
+      <UniqueIdentifier>{784368be-88aa-3170-1479-48fdf8fbc7be}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\grpclb\proto">
-      <UniqueIdentifier>{a7c27f6b-6d15-01cf-76d9-c30dddea0990}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb">
+      <UniqueIdentifier>{82e39ac8-1993-6894-efed-651068234a28}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\grpclb\proto\grpc">
-      <UniqueIdentifier>{bc714e6d-8aba-91df-7db9-7f189f05a6ff}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto">
+      <UniqueIdentifier>{ff02fee6-7304-df5f-76a6-008b5a1c7d19}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\grpclb\proto\grpc\lb">
-      <UniqueIdentifier>{adf7e553-94ef-14fd-e845-03104f00a06f}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc">
+      <UniqueIdentifier>{953a74cb-cafd-eedd-8d34-038c28daf188}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1">
-      <UniqueIdentifier>{bc357e2d-8ddd-a688-88a3-255228fc0818}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb">
+      <UniqueIdentifier>{595a1701-eb5a-e8af-ffa3-f67c0e380894}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\pick_first">
-      <UniqueIdentifier>{b63ded00-b24f-708e-333f-ce199e421875}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1">
+      <UniqueIdentifier>{af8e2597-93ef-1381-d773-082a85e7eaf1}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\round_robin">
-      <UniqueIdentifier>{2472d352-cf94-f317-646e-72b769cea846}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\pick_first">
+      <UniqueIdentifier>{9a3e8049-bc04-8341-5173-6fe5f8a4465c}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\load_reporting">
-      <UniqueIdentifier>{b6c863cd-a135-32e8-df03-02365f526f0d}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\round_robin">
+      <UniqueIdentifier>{6d3d5842-8257-9c58-7985-75f4d98b7d5c}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\resolver">
-      <UniqueIdentifier>{6bfa6808-9dcb-8990-deed-5cf58a149dda}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\resolver">
+      <UniqueIdentifier>{c9873fec-2f83-0497-6d0a-bd9c1cc63be3}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\resolver\dns">
-      <UniqueIdentifier>{e8fe6413-ab8c-48d5-2c7b-aa79e3db4ab2}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\resolver\dns">
+      <UniqueIdentifier>{91b79502-da45-f80b-933e-c974b089db5c}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\resolver\dns\c_ares">
-      <UniqueIdentifier>{2b72688f-79b8-05dd-2896-c7d5dec07dd6}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\resolver\dns\c_ares">
+      <UniqueIdentifier>{73d42c09-d1b5-2e4e-ef12-d74d8ee33ac2}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\resolver\dns\native">
-      <UniqueIdentifier>{94e34be0-29d2-1731-3c1e-617ec4986acb}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\resolver\dns\native">
+      <UniqueIdentifier>{9b2d7e1f-b78a-2e7a-3000-944e46a5fab9}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\resolver\sockaddr">
-      <UniqueIdentifier>{98c1ccc2-2c91-a3d2-6040-a2e15993d51a}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\resolver\sockaddr">
+      <UniqueIdentifier>{bd317dd5-323e-5b27-4c05-d85786be36ab}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\load_reporting">
+      <UniqueIdentifier>{12559ba7-9445-92ae-0c5a-2d79570d4c9b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\max_age">
+      <UniqueIdentifier>{5369e83c-4625-fc14-cc40-9db5da3a7af4}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\ext\transport">
       <UniqueIdentifier>{e3abfd0a-064e-0f2f-c8e8-7c5a7e98142a}</UniqueIdentifier>
diff --git a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
index 05165d6..a3d5b26 100644
--- a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
+++ b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
@@ -163,11 +163,15 @@
     <ClInclude Include="$(SolutionDir)\..\src\compiler\objective_c_generator_helpers.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\php_generator.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\php_generator_helpers.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\protobuf_plugin.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\python_generator.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\python_generator_helpers.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\python_private_generator.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\ruby_generator.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\ruby_generator_helpers-inl.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\ruby_generator_map-inl.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\ruby_generator_string-inl.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\schema_interface.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\src\compiler\cpp_generator.cc">
diff --git a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
index c8b8932..8fa3a0f 100644
--- a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
@@ -65,9 +65,18 @@
     <ClInclude Include="$(SolutionDir)\..\src\compiler\php_generator_helpers.h">
       <Filter>src\compiler</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\protobuf_plugin.h">
+      <Filter>src\compiler</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\compiler\python_generator.h">
       <Filter>src\compiler</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\python_generator_helpers.h">
+      <Filter>src\compiler</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\python_private_generator.h">
+      <Filter>src\compiler</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\compiler\ruby_generator.h">
       <Filter>src\compiler</Filter>
     </ClInclude>
@@ -80,6 +89,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\compiler\ruby_generator_string-inl.h">
       <Filter>src\compiler</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\schema_interface.h">
+      <Filter>src\compiler</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index bc018dc..c675cda 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -207,7 +207,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
@@ -370,8 +369,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.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 6a02b15..c6bd2d6 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -94,9 +94,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -614,9 +611,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 83e7658..8799359 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -302,7 +302,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
@@ -422,32 +421,32 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\retry_throttle.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel_index.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\uri_parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_ev_driver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_wrapper.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_common.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.h" />
@@ -468,6 +467,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_status.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\trace_string.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
@@ -496,8 +496,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
@@ -778,67 +776,67 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\channel_connectivity.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\channel_connectivity.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_plugin.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_plugin.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\retry_throttle.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel_index.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\uri_parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\dns_resolver_ares.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_wrapper.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\native\dns_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\sockaddr\sockaddr_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\sockaddr\sockaddr_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb_channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
     </ClCompile>
@@ -846,9 +844,9 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\pick_first\pick_first.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\pick_first\pick_first.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\round_robin\round_robin.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\round_robin\round_robin.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
     </ClCompile>
@@ -878,6 +876,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_unsecure_plugin_registry.c">
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 5e2b7c2..cf2def4 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -40,9 +40,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.c">
-      <Filter>src\core\lib\channel</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -463,98 +460,98 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.c">
       <Filter>src\core\ext\transport\chttp2\client</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\channel_connectivity.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\channel_connectivity.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_plugin.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_plugin.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_factory.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_registry.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_registry.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\retry_throttle.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel_index.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\uri_parser.c">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.c">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\dns_resolver_ares.c">
-      <Filter>src\core\ext\resolver\dns\c_ares</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
-      <Filter>src\core\ext\resolver\dns\c_ares</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_wrapper.c">
-      <Filter>src\core\ext\resolver\dns\c_ares</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\dns\native\dns_resolver.c">
-      <Filter>src\core\ext\resolver\dns\native</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\native</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\resolver\sockaddr\sockaddr_resolver.c">
-      <Filter>src\core\ext\resolver\sockaddr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\sockaddr\sockaddr_resolver.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\sockaddr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.c">
-      <Filter>src\core\ext\load_reporting</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.c">
+      <Filter>src\core\ext\filters\load_reporting</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.c">
-      <Filter>src\core\ext\load_reporting</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.c">
+      <Filter>src\core\ext\filters\load_reporting</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb_channel.c">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
-      <Filter>src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
       <Filter>third_party\nanopb</Filter>
@@ -565,11 +562,11 @@
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.c">
       <Filter>third_party\nanopb</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\pick_first\pick_first.c">
-      <Filter>src\core\ext\lb_policy\pick_first</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\pick_first\pick_first.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\pick_first</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\round_robin\round_robin.c">
-      <Filter>src\core\ext\lb_policy\round_robin</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\round_robin\round_robin.c">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\round_robin</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
       <Filter>src\core\ext\census</Filter>
@@ -613,6 +610,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
       <Filter>src\core\ext\census</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.c">
+      <Filter>src\core\ext\filters\max_age</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_unsecure_plugin_registry.c">
       <Filter>src\core\plugin_registry</Filter>
     </ClCompile>
@@ -746,9 +746,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\max_age_filter.h">
-      <Filter>src\core\lib\channel</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
@@ -1106,83 +1103,83 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h">
       <Filter>src\core\ext\transport\chttp2\client</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\client_channel_factory.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\connector.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_connect_handshaker.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_connect_handshaker.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\http_proxy.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\http_proxy.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_factory.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_factory.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\lb_policy_registry.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy_registry.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\parse_address.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\parse_address.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\proxy_mapper_registry.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\proxy_mapper_registry.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_factory.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_factory.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\resolver_registry.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver_registry.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\retry_throttle.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\retry_throttle.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\subchannel_index.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\uri_parser.h">
-      <Filter>src\core\ext\client_channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h">
+      <Filter>src\core\ext\filters\client_channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_ev_driver.h">
-      <Filter>src\core\ext\resolver\dns\c_ares</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\resolver\dns\c_ares\grpc_ares_wrapper.h">
-      <Filter>src\core\ext\resolver\dns\c_ares</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.h">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.h">
-      <Filter>src\core\ext\load_reporting</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting.h">
+      <Filter>src\core\ext\filters\load_reporting</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.h">
-      <Filter>src\core\ext\load_reporting</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\load_reporting\load_reporting_filter.h">
+      <Filter>src\core\ext\filters\load_reporting</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.h">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb_channel.h">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.h">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h">
-      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\load_balancer_api.h">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h">
-      <Filter>src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h">
+      <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h">
       <Filter>third_party\nanopb</Filter>
@@ -1244,6 +1241,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h">
+      <Filter>src\core\ext\filters\max_age</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
@@ -1274,50 +1274,56 @@
     <Filter Include="src\core\ext\census\gen">
       <UniqueIdentifier>{dfe53168-57b0-3ac4-d8ba-07fd958cc8f5}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\client_channel">
-      <UniqueIdentifier>{2edd1aad-34cf-0c66-e03e-b1b2dd81d9a8}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters">
+      <UniqueIdentifier>{5e37012e-a374-e285-bbda-b0dbe6327663}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy">
-      <UniqueIdentifier>{a23781d2-27e4-7cb0-12cd-59782ecb21ce}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel">
+      <UniqueIdentifier>{bb0de45a-745e-8822-7ad5-453f9e060f8c}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\grpclb">
-      <UniqueIdentifier>{25a465c8-d1e8-6248-c005-bb2062206472}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy">
+      <UniqueIdentifier>{2ac0872e-12dc-0b08-68e0-66829ce8c268}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\grpclb\proto">
-      <UniqueIdentifier>{40fc2615-d244-0d36-4486-ba6f0fa468bb}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb">
+      <UniqueIdentifier>{6cc603b0-7272-0a9f-59c2-5561c1856a6a}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\grpclb\proto\grpc">
-      <UniqueIdentifier>{1d129f24-a399-12ef-68de-023aff7dde52}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto">
+      <UniqueIdentifier>{0d3bc4ed-1eea-8b17-c26f-7d87c3dd2220}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\grpclb\proto\grpc\lb">
-      <UniqueIdentifier>{21858d9d-30b5-8847-5882-6b47df0fa293}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc">
+      <UniqueIdentifier>{32d37957-d122-e649-b9c1-3f13f6674479}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1">
-      <UniqueIdentifier>{e9256e96-ea3d-c1fd-6426-9d53d9f08f66}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb">
+      <UniqueIdentifier>{153a159f-1ba7-aea7-ebed-4f2d9e2e7bb9}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\pick_first">
-      <UniqueIdentifier>{e27f9ecf-97bb-1a2e-3135-a41f732dcf55}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\grpclb\proto\grpc\lb\v1">
+      <UniqueIdentifier>{f8747b87-02f9-df6c-0eeb-27ab1d037d0c}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\lb_policy\round_robin">
-      <UniqueIdentifier>{e5fc1091-5d60-404f-775b-686ef4b3266f}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\pick_first">
+      <UniqueIdentifier>{4df776ac-ebeb-4933-554e-749a0399ff51}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\load_reporting">
-      <UniqueIdentifier>{2d6e3879-24c7-06e2-b415-40ab18a3b918}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\lb_policy\round_robin">
+      <UniqueIdentifier>{5244539b-6cec-80c7-61dc-df51e531bedd}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\resolver">
-      <UniqueIdentifier>{88c78e27-267a-95df-07c5-50e5fbc2f40c}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\resolver">
+      <UniqueIdentifier>{663be499-ce6c-8afd-db98-674f26be1149}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\resolver\dns">
-      <UniqueIdentifier>{2e0a9b4f-6394-7c0e-6e5a-0f8b3ee29b41}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\resolver\dns">
+      <UniqueIdentifier>{f6bf03da-fa0d-0c24-bba2-17dc5a3c8fe0}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\resolver\dns\c_ares">
-      <UniqueIdentifier>{932d8afd-e042-46d0-30c5-1c45386165d9}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\resolver\dns\c_ares">
+      <UniqueIdentifier>{54bc0ac2-39c8-dbfd-c5dd-b9fb597dd820}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\resolver\dns\native">
-      <UniqueIdentifier>{3d5398c8-928b-9096-8eb7-f8c40ee68c4d}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\resolver\dns\native">
+      <UniqueIdentifier>{55f499bd-ae18-5210-81e1-385c85e60875}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\ext\resolver\sockaddr">
-      <UniqueIdentifier>{71686ed0-fbf9-02a4-d65a-a73f7dc4e2be}</UniqueIdentifier>
+    <Filter Include="src\core\ext\filters\client_channel\resolver\sockaddr">
+      <UniqueIdentifier>{99210f5e-b2a0-ecd1-024f-fc152db68a11}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\load_reporting">
+      <UniqueIdentifier>{0aef07b4-39d2-f862-15ac-65b4bf00dabb}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\ext\filters\max_age">
+      <UniqueIdentifier>{d3bc80c1-5f2d-e842-42ac-43d8a6ada8de}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\ext\transport">
       <UniqueIdentifier>{967c89fe-c97c-27e2-aac0-9ba5854cb5fa}</UniqueIdentifier>
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 5a2d6ac..e3adf79 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
@@ -159,6 +159,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_hostname.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_ping.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\binary_metadata.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\cancel_after_accept.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 3a870b9..cfb8d04 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
@@ -13,6 +13,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_hostname.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_ping.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\binary_metadata.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 4b001a7..a67f509 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
@@ -159,6 +159,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_hostname.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_ping.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\binary_metadata.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\call_creds.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 2eace64..97ba77a 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
@@ -13,6 +13,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_hostname.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\bad_ping.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\binary_metadata.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>