Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 16 additions & 19 deletions syncd/FlexCounter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,24 +990,21 @@ class CounterContext : public BaseCounterContext
auto rid = rids[i];
auto vid = vids[i];
std::vector<uint64_t> stats(counter_ids.size());
if (collectData(rid, counter_ids, effective_stats_mode, false, stats)) {

auto it_vid = m_objectIdsMap.find(vid);
if (it_vid != m_objectIdsMap.end())
{
// Remove and re-add if vid already exists
m_objectIdsMap.erase(it_vid);
}

auto counter_data = std::make_shared<CounterIds<StatType>>(rid, counter_ids);
m_objectIdsMap.emplace(vid, counter_data);

SWSS_LOG_INFO("Fallback to single call for object 0x%" PRIx64, vid);
} else {
SWSS_LOG_WARN("%s RID %s can't provide the statistic", m_name.c_str(), sai_serialize_object_id(rid).c_str());
if (!collectData(rid, counter_ids, effective_stats_mode, false, stats))
{
SWSS_LOG_INFO("counter read failed on RID 0x%x on intf 0x%x, adding to objectIdsMap regardless", rid, vid);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Format-specifier bug (UB). rid and vid are sai_object_id_t = uint64_t, but 0x%x is a 32-bit unsigned int specifier. Passing a uint64_t to %x is undefined behavior and will misprint/truncate the OID (you'll get the wrong half of the 64-bit value, and on some ABIs the second arg shifts) — which defeats the log's purpose when someone is debugging which port failed. The file's own convention is right here in the same function: use 0x%\" PRIx64 (cf. the Fallback to single call for object 0x%\" PRIx64 lines just above) or sai_serialize_object_id(rid).c_str(). Suggest:

SWSS_LOG_INFO("counter read failed on RID 0x%\" PRIx64 \" on intf 0x%\" PRIx64 \", adding to objectIdsMap regardless", rid, vid);

(Same fix needed on the sibling line in the main collectData loop ~1162.)

}
auto it_vid = m_objectIdsMap.find(vid);
if (it_vid != m_objectIdsMap.end())
{
// Remove and re-add if vid already exists
m_objectIdsMap.erase(it_vid);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 This now inserts into m_objectIdsMap unconditionally (previously gated behind a successful collectData). Consistent with the workaround's intent (poll regardless), but it means an object whose counters genuinely never succeed stays in the map and is polled+fails every interval (now at INFO). Bounded and intended — worth a one-line comment that the unconditional insert is deliberate, so a future reader doesn't mistake it for the success-gating that was here before.

}
}

auto counter_data = std::make_shared<CounterIds<StatType>>(rid, counter_ids);
m_objectIdsMap.emplace(vid, counter_data);
SWSS_LOG_INFO("Fallback to single call for object 0x%" PRIx64, vid);
}
return;
}

Expand Down Expand Up @@ -1159,10 +1156,10 @@ class CounterContext : public BaseCounterContext
kv.second->getStatsMode() == SAI_STATS_MODE_READ_AND_CLEAR) ? SAI_STATS_MODE_READ_AND_CLEAR : SAI_STATS_MODE_READ;
}

std::vector<uint64_t> stats(statIds.size());
if (!collectData(rid, statIds, effective_stats_mode, true, stats))
std::vector<uint64_t> stats(statIds.size(), 0);
if (!collectData(rid, statIds, effective_stats_mode, false, stats))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Semantic behavior change worth an explicit comment. The old code did continue on a failed read — leaving the previous Redis value in place. This now writes 0 for every counter on failure. For management ports that never support the counter, zeros-forever is exactly the intended fix. But for a normal port with a transient SAI hiccup, this publishes a spurious 0, which downstream rate math (show interface counters, SNMP, gNMI) reads as a counter reset to zero — a false "counters cleared"/traffic-stopped blip, plus a rate spike on the next good poll as the value jumps back. Since this is an acknowledged temp workaround that may be an accepted tradeoff, but it affects all ports (not just management), please add a code comment noting the intentional "publish 0 on read failure" behavior so it's documented rather than a field surprise. The proper fix (#1774) avoids this by only polling per-port-supported counters.

{
continue;
SWSS_LOG_INFO("counter read failed on RID 0x%x on intf 0x%x, filling with '0' value", rid, vid);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Same %x-for-uint64_t UB as line 995 — fix this one too:

SWSS_LOG_INFO("counter read failed on RID 0x%\" PRIx64 \" on intf 0x%\" PRIx64 \", filling with '0' value", rid, vid);

}

std::vector<swss::FieldValueTuple> values;
Expand Down
Loading