in fboss/agent/hw/bcm/BcmPort.cpp [1199:1349]
void BcmPort::updateStats() {
auto lockedPortStatsPtr = portStats_.wlock();
if (!lockedPortStatsPtr->has_value()) {
return;
}
// TODO: It would be nicer to use a monotonic clock, but unfortunately
// the ServiceData code currently expects everyone to use system time.
auto now = duration_cast<seconds>(system_clock::now().time_since_epoch());
HwPortStats curPortStats, lastPortStats;
lastPortStats = curPortStats = (*lockedPortStatsPtr)->portStats();
// All stats start with a unitialized (-1) value. If there are no in discards
// we will just report that as the monotonic counter. Instead set it to
// 0 if uninintialized
*curPortStats.inDiscards_() = *curPortStats.inDiscards_() ==
hardware_stats_constants::STAT_UNINITIALIZED()
? 0
: *curPortStats.inDiscards_();
curPortStats.timestamp_() = now.count();
updateStat(now, kInBytes(), snmpIfHCInOctets, &(*curPortStats.inBytes_()));
updateStat(
now,
kInUnicastPkts(),
snmpIfHCInUcastPkts,
&(*curPortStats.inUnicastPkts_()));
updateStat(
now,
kInMulticastPkts(),
snmpIfHCInMulticastPkts,
&(*curPortStats.inMulticastPkts_()));
updateStat(
now,
kInBroadcastPkts(),
snmpIfHCInBroadcastPkts,
&(*curPortStats.inBroadcastPkts_()));
updateStat(
now,
kInDiscardsRaw(),
snmpIfInDiscards,
&(*curPortStats.inDiscardsRaw_()));
updateStat(now, kInErrors(), snmpIfInErrors, &(*curPortStats.inErrors_()));
updateStat(
now,
kInIpv4HdrErrors(),
snmpIpInHdrErrors,
&(*curPortStats.inIpv4HdrErrors_()));
updateStat(
now,
kInIpv6HdrErrors(),
snmpIpv6IfStatsInHdrErrors,
&(*curPortStats.inIpv6HdrErrors_()));
updateStat(
now, kInPause(), snmpDot3InPauseFrames, &(*curPortStats.inPause_()));
// Egress Stats
updateStat(now, kOutBytes(), snmpIfHCOutOctets, &(*curPortStats.outBytes_()));
updateStat(
now,
kOutUnicastPkts(),
snmpIfHCOutUcastPkts,
&(*curPortStats.outUnicastPkts_()));
updateStat(
now,
kOutMulticastPkts(),
snmpIfHCOutMulticastPkts,
&(*curPortStats.outMulticastPkts_()));
updateStat(
now,
kOutBroadcastPkts(),
snmpIfHCOutBroadcastPckts,
&(*curPortStats.outBroadcastPkts_()));
updateStat(
now, kOutDiscards(), snmpIfOutDiscards, &(*curPortStats.outDiscards_()));
updateStat(now, kOutErrors(), snmpIfOutErrors, &(*curPortStats.outErrors_()));
updateStat(
now, kOutPause(), snmpDot3OutPauseFrames, &(*curPortStats.outPause_()));
if (hw_->getPlatform()->getAsic()->isSupported(HwAsic::Feature::ECN)) {
// ECN stats not supported by TD2
updateStat(
now,
kOutEcnCounter(),
snmpBcmTxEcnErrors,
&(*curPortStats.outEcnCounter_()));
}
updateStat(
now,
kInDstNullDiscards(),
snmpBcmCustomReceive3,
&(*curPortStats.inDstNullDiscards_()));
auto settings = getProgrammedSettings();
if (settings && settings->getPfc().has_value()) {
updatePortPfcStats(now, curPortStats, settings->getPfcPriorities());
}
updateFecStats(now, curPortStats);
updateFdrStats(now);
updateWredStats(now, &(*curPortStats.wredDroppedPackets_()));
queueManager_->updateQueueStats(now, &curPortStats);
std::vector<utility::CounterPrevAndCur> toSubtractFromInDiscardsRaw = {
{*lastPortStats.inDstNullDiscards_(),
*curPortStats.inDstNullDiscards_()}};
if (isMmuLossy()) {
// If MMU setup as lossy, all incoming pause frames will be
// discarded and will count towards in discards. This makes in discards
// counter somewhat useless. So instead calculate "in_non_pause_discards",
// by subtracting the pause frames received from in_discards.
// TODO: Test if this is true when rx pause is enabled
toSubtractFromInDiscardsRaw.emplace_back(
*lastPortStats.inPause_(), *curPortStats.inPause_());
}
// as with pause, remove incoming PFC frames from the discards
// as well
if (curPortStats.inPfcCtrl_() !=
hardware_stats_constants::STAT_UNINITIALIZED()) {
toSubtractFromInDiscardsRaw.emplace_back(
*lastPortStats.inPfcCtrl_(), *curPortStats.inPfcCtrl_());
}
*curPortStats.inDiscards_() += utility::subtractIncrements(
{*lastPortStats.inDiscardsRaw_(), *curPortStats.inDiscardsRaw_()},
toSubtractFromInDiscardsRaw);
auto inDiscards = getPortCounterIf(kInDiscards());
inDiscards->updateValue(now, *curPortStats.inDiscards_());
*lockedPortStatsPtr = BcmPortStats(curPortStats, now);
// Update the queue length stat
uint32_t qlength;
auto ret = bcm_port_queued_count_get(unit_, port_, &qlength);
if (BCM_FAILURE(ret)) {
XLOG(ERR) << "Failed to get queue length for port " << port_ << " :"
<< bcm_errmsg(ret);
} else {
outQueueLen_.addValue(now.count(), qlength);
// TODO: outQueueLen_ only exports the average queue length over the last
// 60 seconds, 10 minutes, etc.
// We should also export the current value. We could use a simple counter
// or a dynamic counter for this.
}
// Update the packet length histograms
updatePktLenHist(now, &inPktLengths_, kInPktLengthStats);
updatePktLenHist(now, &outPktLengths_, kOutPktLengthStats);
// Update any platform specific port counters
getPlatformPort()->updateStats();
};