blob: c238d925db6b32e4e8aafb104a95648e93685e58 [file] [log] [blame]
Harshit Aghera560e6af2025-04-21 20:04:56 +05301/*
2 * SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION &
3 * AFFILIATES. All rights reserved.
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include "MctpRequester.hpp"
8
9#include <linux/mctp.h>
10#include <sys/socket.h>
11
12#include <OcpMctpVdm.hpp>
13#include <boost/asio/buffer.hpp>
14#include <boost/asio/error.hpp>
15#include <boost/asio/generic/datagram_protocol.hpp>
16#include <boost/asio/io_context.hpp>
17#include <boost/asio/steady_timer.hpp>
18#include <phosphor-logging/lg2.hpp>
19
20#include <cerrno>
21#include <cstddef>
22#include <cstdint>
23#include <cstring>
24#include <functional>
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +053025#include <memory>
Harshit Aghera560e6af2025-04-21 20:04:56 +053026#include <span>
27#include <utility>
28
29using namespace std::literals;
30
31namespace mctp
32{
33
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +053034Requester::Requester(boost::asio::io_context& ctx) :
Harshit Aghera560e6af2025-04-21 20:04:56 +053035 mctpSocket(ctx, boost::asio::generic::datagram_protocol{AF_MCTP, 0}),
36 expiryTimer(ctx)
37{}
38
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +053039void Requester::processRecvMsg(
Harshit Aghera560e6af2025-04-21 20:04:56 +053040 uint8_t eid, const std::span<const uint8_t> reqMsg,
41 const std::span<uint8_t> respMsg, const boost::system::error_code& ec,
42 const size_t /*length*/)
43{
44 expiryTimer.cancel();
45
46 if (ec)
47 {
48 lg2::error(
49 "MctpRequester failed to receive data from the MCTP socket - ErrorCode={EC}, Error={ER}.",
50 "EC", ec.value(), "ER", ec.message());
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +053051 completionCallbacks[eid](EIO);
Harshit Aghera560e6af2025-04-21 20:04:56 +053052 return;
53 }
54
55 const auto* respAddr =
56 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
57 reinterpret_cast<const struct sockaddr_mctp*>(recvEndPoint.data());
58
59 if (respAddr->smctp_type != msgType)
60 {
61 lg2::error("MctpRequester: Message type mismatch");
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +053062 completionCallbacks[eid](EPROTO);
Harshit Aghera560e6af2025-04-21 20:04:56 +053063 return;
64 }
65
66 uint8_t respEid = respAddr->smctp_addr.s_addr;
67
68 if (respEid != eid)
69 {
70 lg2::error(
71 "MctpRequester: EID mismatch - expected={EID}, received={REID}",
72 "EID", eid, "REID", respEid);
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +053073 completionCallbacks[eid](EPROTO);
Harshit Aghera560e6af2025-04-21 20:04:56 +053074 return;
75 }
76
77 if (respMsg.size() > sizeof(ocp::accelerator_management::BindingPciVid))
78 {
79 const auto* reqHdr =
80 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
81 reinterpret_cast<const ocp::accelerator_management::BindingPciVid*>(
82 reqMsg.data());
83
84 uint8_t reqInstanceId = reqHdr->instance_id &
85 ocp::accelerator_management::instanceIdBitMask;
86 const auto* respHdr =
87 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
88 reinterpret_cast<const ocp::accelerator_management::BindingPciVid*>(
89 respMsg.data());
90
91 uint8_t respInstanceId = respHdr->instance_id &
92 ocp::accelerator_management::instanceIdBitMask;
93
94 if (reqInstanceId != respInstanceId)
95 {
96 lg2::error(
97 "MctpRequester: Instance ID mismatch - request={REQ}, response={RESP}",
98 "REQ", static_cast<int>(reqInstanceId), "RESP",
99 static_cast<int>(respInstanceId));
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +0530100 completionCallbacks[eid](EPROTO);
Harshit Aghera560e6af2025-04-21 20:04:56 +0530101 return;
102 }
103 }
104
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +0530105 completionCallbacks[eid](0);
Harshit Aghera560e6af2025-04-21 20:04:56 +0530106}
107
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +0530108void Requester::handleSendMsgCompletion(
Harshit Aghera560e6af2025-04-21 20:04:56 +0530109 uint8_t eid, const std::span<const uint8_t> reqMsg,
110 std::span<uint8_t> respMsg, const boost::system::error_code& ec,
111 size_t /* length */)
112{
113 if (ec)
114 {
115 lg2::error(
116 "MctpRequester failed to send data from the MCTP socket - ErrorCode={EC}, Error={ER}.",
117 "EC", ec.value(), "ER", ec.message());
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +0530118 completionCallbacks[eid](EIO);
Harshit Aghera560e6af2025-04-21 20:04:56 +0530119 return;
120 }
121
122 expiryTimer.expires_after(2s);
123
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +0530124 expiryTimer.async_wait([this, eid](const boost::system::error_code& ec) {
Harshit Aghera560e6af2025-04-21 20:04:56 +0530125 if (ec != boost::asio::error::operation_aborted)
126 {
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +0530127 completionCallbacks[eid](ETIME);
Harshit Aghera560e6af2025-04-21 20:04:56 +0530128 }
129 });
130
131 mctpSocket.async_receive_from(
132 boost::asio::mutable_buffer(respMsg), recvEndPoint,
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +0530133 std::bind_front(&Requester::processRecvMsg, this, eid, reqMsg,
Harshit Aghera560e6af2025-04-21 20:04:56 +0530134 respMsg));
135}
136
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +0530137void Requester::sendRecvMsg(uint8_t eid, const std::span<const uint8_t> reqMsg,
138 std::span<uint8_t> respMsg,
139 std::move_only_function<void(int)> callback)
Harshit Aghera560e6af2025-04-21 20:04:56 +0530140{
141 if (reqMsg.size() < sizeof(ocp::accelerator_management::BindingPciVid))
142 {
143 lg2::error("MctpRequester: Message too small");
144 callback(EPROTO);
145 return;
146 }
147
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +0530148 completionCallbacks[eid] = std::move(callback);
Harshit Aghera560e6af2025-04-21 20:04:56 +0530149
150 struct sockaddr_mctp addr{};
151 addr.smctp_family = AF_MCTP;
152 addr.smctp_addr.s_addr = eid;
153 addr.smctp_type = msgType;
154 addr.smctp_tag = MCTP_TAG_OWNER;
155
156 sendEndPoint = {&addr, sizeof(addr)};
157
158 mctpSocket.async_send_to(
159 boost::asio::const_buffer(reqMsg), sendEndPoint,
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +0530160 std::bind_front(&Requester::handleSendMsgCompletion, this, eid, reqMsg,
161 respMsg));
Harshit Aghera560e6af2025-04-21 20:04:56 +0530162}
Aditya Kurdunkar1213bcb2025-06-11 04:38:52 +0530163
164void QueuingRequester::sendRecvMsg(uint8_t eid, std::span<const uint8_t> reqMsg,
165 std::span<uint8_t> respMsg,
166 std::move_only_function<void(int)> callback)
167{
168 auto reqCtx =
169 std::make_unique<RequestContext>(reqMsg, respMsg, std::move(callback));
170
171 // Add request to queue
172 auto& queue = requestContextQueues[eid];
173 queue.push(std::move(reqCtx));
174
175 processQueue(eid);
176}
177
178void QueuingRequester::processQueue(uint8_t eid)
179{
180 auto& queue = requestContextQueues[eid];
181 if (queue.empty() || activeRequestContexts.contains(eid))
182 {
183 return;
184 }
185
186 activeRequestContexts[eid] = std::move(queue.front());
187 queue.pop();
188
189 const auto& reqCtx = activeRequestContexts[eid];
190
191 requester.sendRecvMsg(
192 eid, reqCtx->reqMsg, reqCtx->respMsg, [this, eid](int result) {
193 const auto& reqCtx = activeRequestContexts[eid];
194
195 reqCtx->callback(result); // Call the original callback
196
197 activeRequestContexts.erase(eid);
198
199 processQueue(eid);
200 });
201}
202
Harshit Aghera560e6af2025-04-21 20:04:56 +0530203} // namespace mctp