WIP
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index f440069..30a8030 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -66,36 +66,66 @@
 typedef std::chrono::high_resolution_clock grpc_time_source;
 typedef std::chrono::time_point<grpc_time_source> grpc_time;
 
+namespace ClientRequestCreation {
+template <class RequestType>
+void CreateRequest(RequestType *req, const PayloadConfig&) {
+  // this template must be specialized
+  // fail with an assertion rather than a compile-time
+  // check since these only happen at the beginning anyway
+  GPR_ASSERT(false);
+}
+    
+template <>
+void CreateRequest<SimpleRequest>(SimpleRequest *req, const PayloadConfig& payload_config) {
+  if (payload_config.has_bytebuf_params()) {
+    GPR_ASSERT(false);  // not appropriate for this specialization
+  } else if (payload_config.has_simple_params()) {
+    req->set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
+    req->set_response_size(payload_config.simple_params().resp_size());
+    req->mutable_payload()->set_type(grpc::testing::PayloadType::COMPRESSABLE);
+    int size = payload_config.simple_params().req_size();
+    std::unique_ptr<char[]> body(new char[size]);
+    req->mutable_payload()->set_body(body.get(), size);
+  } else if (payload_config.has_complex_params()) {
+    GPR_ASSERT(false);  // not appropriate for this specialization
+  } else {
+    // default should be simple proto without payloads
+    req->set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
+    req->set_response_size(0);
+    req->mutable_payload()->set_type(grpc::testing::PayloadType::COMPRESSABLE);
+  }
+}
+template <>
+void CreateRequest<ByteBuffer>(ByteBuffer *req, const PayloadConfig& payload_config) {
+  if (payload_config.has_bytebuf_params()) {
+    if (payload_config.req_size() > 0) {
+      std::unique_ptr<char> buf(new char[payload_config.req_size()]);
+      gpr_slice_from_copied_buffer(buf.get(), payload_config.req_size());
+      Slice slice(s, Slice::STEAL_REF);
+      std::unique_ptr<ByteBuffer> bbuf(new ByteBuffer(&slice, 1));
+      req->MoveFrom(bbuf.get());
+    } else {
+      GPR_ASSERT(false);  // not appropriate for this specialization
+    }
+  }
+}
+}
+ 
+template <class StubType, class RequestType>
 class Client {
  public:
-  explicit Client(const ClientConfig& config)
+   Client(const ClientConfig& config,
+	  std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)> create_stub)
       : channels_(config.client_channels()),
+        create_stub_(create_stub),
         timer_(new Timer),
         interarrival_timer_() {
     for (int i = 0; i < config.client_channels(); i++) {
       channels_[i].init(config.server_targets(i % config.server_targets_size()),
                         config);
     }
-    if (config.payload_config().has_bytebuf_params()) {
-      GPR_ASSERT(false);  // not yet implemented
-    } else if (config.payload_config().has_simple_params()) {
-      request_.set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
-      request_.set_response_size(
-          config.payload_config().simple_params().resp_size());
-      request_.mutable_payload()->set_type(
-          grpc::testing::PayloadType::COMPRESSABLE);
-      int size = config.payload_config().simple_params().req_size();
-      std::unique_ptr<char[]> body(new char[size]);
-      request_.mutable_payload()->set_body(body.get(), size);
-    } else if (config.payload_config().has_complex_params()) {
-      GPR_ASSERT(false);  // not yet implemented
-    } else {
-      // default should be simple proto without payloads
-      request_.set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
-      request_.set_response_size(0);
-      request_.mutable_payload()->set_type(
-          grpc::testing::PayloadType::COMPRESSABLE);
-    }
+
+    ClientRequestCreation::CreateRequest<RequestType>(&request_, config.payload_config());
   }
   virtual ~Client() {}
 
@@ -134,7 +164,7 @@
   }
 
  protected:
-  SimpleRequest request_;
+  RequestType request_;
   bool closed_loop_;
 
   class ClientChannelInfo {
@@ -154,16 +184,17 @@
           target, config.security_params().server_host_override(),
           config.has_security_params(),
           !config.security_params().use_test_ca());
-      stub_ = BenchmarkService::NewStub(channel_);
+      stub_ = create_stub_(channel_);
     }
     Channel* get_channel() { return channel_.get(); }
-    BenchmarkService::Stub* get_stub() { return stub_.get(); }
+    StubType* get_stub() { return stub_.get(); }
 
    private:
     std::shared_ptr<Channel> channel_;
-    std::unique_ptr<BenchmarkService::Stub> stub_;
+    std::unique_ptr<StubType> stub_;
   };
   std::vector<ClientChannelInfo> channels_;
+  std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)> create_stub_;
 
   void StartThreads(size_t num_threads) {
     for (size_t i = 0; i < num_threads; i++) {
@@ -306,7 +337,7 @@
     size_t idx_;
     std::thread impl_;
   };
-
+  
   std::vector<std::unique_ptr<Thread>> threads_;
   std::unique_ptr<Timer> timer_;