|  | @@ -881,6 +881,9 @@ class CallData {
 | 
	
		
			
				|  |  |  // ChannelData::SubchannelWrapper
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +using ServerAddressAttributeMap =
 | 
	
		
			
				|  |  | +    std::map<const char*, std::unique_ptr<ServerAddress::AttributeInterface>>;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  // This class is a wrapper for Subchannel that hides details of the
 | 
	
		
			
				|  |  |  // channel's implementation (such as the health check service name and
 | 
	
		
			
				|  |  |  // connected subchannel) from the LB policy API.
 | 
	
	
		
			
				|  | @@ -892,11 +895,13 @@ class CallData {
 | 
	
		
			
				|  |  |  class ChannelData::SubchannelWrapper : public SubchannelInterface {
 | 
	
		
			
				|  |  |   public:
 | 
	
		
			
				|  |  |    SubchannelWrapper(ChannelData* chand, Subchannel* subchannel,
 | 
	
		
			
				|  |  | -                    grpc_core::UniquePtr<char> health_check_service_name)
 | 
	
		
			
				|  |  | +                    grpc_core::UniquePtr<char> health_check_service_name,
 | 
	
		
			
				|  |  | +                    ServerAddressAttributeMap attributes)
 | 
	
		
			
				|  |  |        : SubchannelInterface(&grpc_client_channel_routing_trace),
 | 
	
		
			
				|  |  |          chand_(chand),
 | 
	
		
			
				|  |  |          subchannel_(subchannel),
 | 
	
		
			
				|  |  | -        health_check_service_name_(std::move(health_check_service_name)) {
 | 
	
		
			
				|  |  | +        health_check_service_name_(std::move(health_check_service_name)),
 | 
	
		
			
				|  |  | +        attributes_(std::move(attributes)) {
 | 
	
		
			
				|  |  |      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
 | 
	
		
			
				|  |  |        gpr_log(GPR_INFO,
 | 
	
		
			
				|  |  |                "chand=%p: creating subchannel wrapper %p for subchannel %p",
 | 
	
	
		
			
				|  | @@ -974,14 +979,21 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    void ResetBackoff() override { subchannel_->ResetBackoff(); }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  void ThrottleKeepaliveTime(int new_keepalive_time) {
 | 
	
		
			
				|  |  | -    subchannel_->ThrottleKeepaliveTime(new_keepalive_time);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    const grpc_channel_args* channel_args() override {
 | 
	
		
			
				|  |  |      return subchannel_->channel_args();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  const ServerAddress::AttributeInterface* GetAttribute(
 | 
	
		
			
				|  |  | +      const char* key) const override {
 | 
	
		
			
				|  |  | +    auto it = attributes_.find(key);
 | 
	
		
			
				|  |  | +    if (it == attributes_.end()) return nullptr;
 | 
	
		
			
				|  |  | +    return it->second.get();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  void ThrottleKeepaliveTime(int new_keepalive_time) {
 | 
	
		
			
				|  |  | +    subchannel_->ThrottleKeepaliveTime(new_keepalive_time);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    void UpdateHealthCheckServiceName(
 | 
	
		
			
				|  |  |        grpc_core::UniquePtr<char> health_check_service_name) {
 | 
	
		
			
				|  |  |      if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
 | 
	
	
		
			
				|  | @@ -1175,6 +1187,7 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
 | 
	
		
			
				|  |  |    ChannelData* chand_;
 | 
	
		
			
				|  |  |    Subchannel* subchannel_;
 | 
	
		
			
				|  |  |    grpc_core::UniquePtr<char> health_check_service_name_;
 | 
	
		
			
				|  |  | +  ServerAddressAttributeMap attributes_;
 | 
	
		
			
				|  |  |    // Maps from the address of the watcher passed to us by the LB policy
 | 
	
		
			
				|  |  |    // to the address of the WrapperWatcher that we passed to the underlying
 | 
	
		
			
				|  |  |    // subchannel.  This is needed so that when the LB policy calls
 | 
	
	
		
			
				|  | @@ -1349,6 +1362,18 @@ class ChannelData::ConnectivityWatcherRemover {
 | 
	
		
			
				|  |  |  // ChannelData::ClientChannelControlHelper
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +}  // namespace
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Allows accessing the attributes from a ServerAddress.
 | 
	
		
			
				|  |  | +class ChannelServerAddressPeer {
 | 
	
		
			
				|  |  | + public:
 | 
	
		
			
				|  |  | +  static ServerAddressAttributeMap GetAttributes(ServerAddress* address) {
 | 
	
		
			
				|  |  | +    return std::move(address->attributes_);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +namespace {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  class ChannelData::ClientChannelControlHelper
 | 
	
		
			
				|  |  |      : public LoadBalancingPolicy::ChannelControlHelper {
 | 
	
		
			
				|  |  |   public:
 | 
	
	
		
			
				|  | @@ -1362,7 +1387,8 @@ class ChannelData::ClientChannelControlHelper
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    RefCountedPtr<SubchannelInterface> CreateSubchannel(
 | 
	
		
			
				|  |  | -      const grpc_channel_args& args) override {
 | 
	
		
			
				|  |  | +      ServerAddress address, const grpc_channel_args& args) override {
 | 
	
		
			
				|  |  | +    // Determine health check service name.
 | 
	
		
			
				|  |  |      bool inhibit_health_checking = grpc_channel_arg_get_bool(
 | 
	
		
			
				|  |  |          grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false);
 | 
	
		
			
				|  |  |      grpc_core::UniquePtr<char> health_check_service_name;
 | 
	
	
		
			
				|  | @@ -1370,21 +1396,37 @@ class ChannelData::ClientChannelControlHelper
 | 
	
		
			
				|  |  |        health_check_service_name.reset(
 | 
	
		
			
				|  |  |            gpr_strdup(chand_->health_check_service_name_.get()));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    // Remove channel args that should not affect subchannel uniqueness.
 | 
	
		
			
				|  |  |      static const char* args_to_remove[] = {
 | 
	
		
			
				|  |  |          GRPC_ARG_INHIBIT_HEALTH_CHECKING,
 | 
	
		
			
				|  |  |          GRPC_ARG_CHANNELZ_CHANNEL_NODE,
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  | -    grpc_arg arg = SubchannelPoolInterface::CreateChannelArg(
 | 
	
		
			
				|  |  | -        chand_->subchannel_pool_.get());
 | 
	
		
			
				|  |  | +    // Add channel args needed for the subchannel.
 | 
	
		
			
				|  |  | +    absl::InlinedVector<grpc_arg, 3> args_to_add = {
 | 
	
		
			
				|  |  | +        Subchannel::CreateSubchannelAddressArg(&address.address()),
 | 
	
		
			
				|  |  | +        SubchannelPoolInterface::CreateChannelArg(
 | 
	
		
			
				|  |  | +            chand_->subchannel_pool_.get()),
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    if (address.args() != nullptr) {
 | 
	
		
			
				|  |  | +      for (size_t j = 0; j < address.args()->num_args; ++j) {
 | 
	
		
			
				|  |  | +        args_to_add.emplace_back(address.args()->args[j]);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
 | 
	
		
			
				|  |  | -        &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &arg, 1);
 | 
	
		
			
				|  |  | +        &args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove),
 | 
	
		
			
				|  |  | +        args_to_add.data(), args_to_add.size());
 | 
	
		
			
				|  |  | +    gpr_free(args_to_add[0].value.string);
 | 
	
		
			
				|  |  | +    // Create subchannel.
 | 
	
		
			
				|  |  |      Subchannel* subchannel =
 | 
	
		
			
				|  |  |          chand_->client_channel_factory_->CreateSubchannel(new_args);
 | 
	
		
			
				|  |  |      grpc_channel_args_destroy(new_args);
 | 
	
		
			
				|  |  |      if (subchannel == nullptr) return nullptr;
 | 
	
		
			
				|  |  | +    // Make sure the subchannel has updated keepalive time.
 | 
	
		
			
				|  |  |      subchannel->ThrottleKeepaliveTime(chand_->keepalive_time_);
 | 
	
		
			
				|  |  | +    // Create and return wrapper for the subchannel.
 | 
	
		
			
				|  |  |      return MakeRefCounted<SubchannelWrapper>(
 | 
	
		
			
				|  |  | -        chand_, subchannel, std::move(health_check_service_name));
 | 
	
		
			
				|  |  | +        chand_, subchannel, std::move(health_check_service_name),
 | 
	
		
			
				|  |  | +        ChannelServerAddressPeer::GetAttributes(&address));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    void UpdateState(
 | 
	
	
		
			
				|  | @@ -1662,9 +1704,12 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
 | 
	
		
			
				|  |  |                                 &new_args);
 | 
	
		
			
				|  |  |    target_uri_.reset(proxy_name != nullptr ? proxy_name
 | 
	
		
			
				|  |  |                                            : gpr_strdup(server_uri));
 | 
	
		
			
				|  |  | -  channel_args_ = new_args != nullptr
 | 
	
		
			
				|  |  | -                      ? new_args
 | 
	
		
			
				|  |  | -                      : grpc_channel_args_copy(args->channel_args);
 | 
	
		
			
				|  |  | +  // Strip out service config channel arg, so that it doesn't affect
 | 
	
		
			
				|  |  | +  // subchannel uniqueness when the args flow down to that layer.
 | 
	
		
			
				|  |  | +  const char* arg_to_remove = GRPC_ARG_SERVICE_CONFIG;
 | 
	
		
			
				|  |  | +  channel_args_ = grpc_channel_args_copy_and_remove(
 | 
	
		
			
				|  |  | +      new_args != nullptr ? new_args : args->channel_args, &arg_to_remove, 1);
 | 
	
		
			
				|  |  | +  grpc_channel_args_destroy(new_args);
 | 
	
		
			
				|  |  |    keepalive_time_ = grpc_channel_args_find_integer(
 | 
	
		
			
				|  |  |        channel_args_, GRPC_ARG_KEEPALIVE_TIME_MS,
 | 
	
		
			
				|  |  |        {-1 /* default value, unset */, 1, INT_MAX});
 |