blob: 01f95690f58beb7fb83a7294763a3528986042f2 [file] [edit]
/*
* SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
* All rights reserved. SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#pragma once
#include "base.h"
#include <cstdint>
#include <deque>
#include <unordered_map>
#include <vector>
namespace requester
{
using eid_t = uint8_t;
enum class MismatchReason : uint8_t
{
TypeCmdRejected, // instanceId matched but type/cmd wrong
NotFound, // no outstanding request matched
};
// Tracks NSM response mismatches per EID with rate limiting.
// First occurrence of each unique (EID, reason, type/cmd) combination is
// logged immediately with raw bytes. Subsequent identical occurrences
// increment a counter silently. All events are re-emitted on logMismatches(),
// called from NsmLogDumpIntf::logDump() to survive journal rotation.
class ResponseMismatchTracker
{
public:
// instanceId matched but type/cmd wrong; both request and response bytes
// are available for logging.
static void recordTypeCmdRejected(eid_t eid, uint8_t instanceId,
uint8_t expectedType, uint8_t expectedCmd,
uint8_t gotType, uint8_t gotCmd,
const std::vector<uint8_t>& reqBytes,
const uint8_t* respBytes, size_t respLen);
// No outstanding request matched; response bytes only.
static void recordNotFound(eid_t eid, uint8_t tag, uint8_t instanceId,
uint8_t gotType, uint8_t gotCmd,
const uint8_t* respBytes, size_t respLen);
static void logMismatches();
private:
struct MismatchEvent
{
MismatchReason reason;
uint8_t instanceId;
uint8_t expectedType; // 0 for NotFound
uint8_t expectedCmd; // 0 for NotFound
uint8_t gotType;
uint8_t gotCmd;
uint32_t count{1};
};
static constexpr size_t MAX_EVENTS_PER_EID = 10;
static inline std::unordered_map<eid_t, std::deque<MismatchEvent>>
instances;
// If a matching event exists, increments its count and returns true.
// Otherwise evicts oldest if at capacity and returns false (caller must
// push_back a new entry and emit the first-occurrence log).
static bool dedupOrEvict(eid_t eid, MismatchReason reason,
uint8_t expectedType, uint8_t expectedCmd,
uint8_t gotType, uint8_t gotCmd);
static void logEvent(eid_t eid, const MismatchEvent& event);
};
} // namespace requester