blob: ae3c6753d245fa77cc103a27d20da8a863a66dcf [file] [log] [blame]
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __VOM_RPC_CMD_H__
#define __VOM_RPC_CMD_H__
#include <future>
#include "vom/cmd.hpp"
#include "vom/logger.hpp"
namespace VOM {
/**
* A base class for all RPC commands to VPP.
* RPC commands are one of the sub-set of command types to VPP
* that modify/create state in VPP and thus return an error code.
* Commands are issued in one thread context, but read in another. The
* command has an associated std::promise that is met by the RX thread.
* this allows the sender, which waits on the promise's future, to
* experience a synchronous command.
*
* The command is templatised on the type of the HW::item to be set by
* the command, and the data returned in the promise,
*/
template <typename HWITEM, typename DATA, typename MSG>
class rpc_cmd : public cmd
{
public:
/**
* convenient typedef
*/
typedef MSG msg_t;
/**
* Constructor taking the HW item that will be updated by the command
*/
rpc_cmd(HWITEM& item)
: cmd()
, m_hw_item(item)
, m_promise()
{
}
/**
* Desructor
*/
virtual ~rpc_cmd() {}
/**
* return the HW item the command updates
*/
HWITEM& item() { return m_hw_item; }
/**
* return the const HW item the command updates
*/
const HWITEM& item() const { return m_hw_item; }
/**
* Fulfill the commands promise. Called from the RX thread
*/
void fulfill(const DATA& d)
{
m_promise.set_value(d);
/*
* we reset the promise after setting the value to reuse it
* when we run the retire command from the same cmd object
*/
m_promise = std::promise<DATA>();
}
/**
* Wait on the commands promise. i.e. block on the completion
* of the command.
*/
DATA wait()
{
std::future_status status;
std::future<DATA> result;
result = m_promise.get_future();
status = result.wait_for(std::chrono::seconds(5));
if (status != std::future_status::ready) {
return (DATA(rc_t::TIMEOUT));
}
return (result.get());
}
/**
* Called by the HW Command Q when it is disabled to indicate the
* command can be considered successful without issuing it to HW
*/
virtual void succeeded() { m_hw_item.set(rc_t::OK); }
/**
* call operator used as a callback by VAPI when the reply is available
*/
virtual vapi_error_e operator()(MSG& reply)
{
int retval = reply.get_response().get_payload().retval;
VOM_LOG(log_level_t::DEBUG) << to_string() << " " << retval;
fulfill(rc_t::from_vpp_retval(retval));
return (VAPI_OK);
}
/**
* Retire/cancel a long running command
*/
virtual void retire(connection& con) {}
protected:
/**
* A reference to an object's HW::item that the command will update
*/
HWITEM& m_hw_item;
/**
* The promise that implements the synchronous issue
*/
std::promise<DATA> m_promise;
};
};
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/
#endif