Skip to content

[clear] Add 'sonic-clear pfcwdstats' to clear PFC watchdog counters#4634

Open
pinky-nexthop wants to merge 1 commit into
sonic-net:masterfrom
nexthop-ai:mabel.pfcwd-clear-upstream
Open

[clear] Add 'sonic-clear pfcwdstats' to clear PFC watchdog counters#4634
pinky-nexthop wants to merge 1 commit into
sonic-net:masterfrom
nexthop-ai:mabel.pfcwd-clear-upstream

Conversation

@pinky-nexthop

@pinky-nexthop pinky-nexthop commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What I did

There is currently no CLI to clear PFC watchdog statistics. Clearing them is needed when troubleshooting PFC storms — stale counts from a prior event make it hard to tell whether a storm is currently ongoing. show pfcwd stats displays the counters, but there is no corresponding clear command. This PR adds sonic-clear pfcwdstats.

Addresses the PFC-watchdog-counter-clear item in #4595.

How I did it

  • scripts/pfcwdstat: new tool that zeroes the PFC_WD_QUEUE_STATS_* fields in COUNTERS_DB, following the standard counter-clear pattern (pfcstat -c, queuestat -c, …). It enumerates queues via COUNTERS_QUEUE_NAME_MAP — the same source show pfcwd stats uses — so stale stats from queues that are no longer actively monitored (STATUS=N/A) are also cleared.
  • Queues with an active storm (PFC_WD_STATUS == 'stormed') are skipped, so the in-flight DEADLOCK_DETECTED/DEADLOCK_RESTORED pair is not split (which would otherwise leave RESTORED > DETECTED once the storm ends).
  • clear/main.py: adds sonic-clear pfcwdstats, invoking pfcwdstat -c.
  • setup.py: installs scripts/pfcwdstat.
  • Unit tests for the clear command and the pfcwdstat clear logic (including the stale-stats and active-storm cases).

How to verify it

pytest tests/pfcwd_test.py::TestPfcwdstatClear tests/clear_test.py -k pfcwd

Manually: show pfcwd stats to see counts, sonic-clear pfcwdstats to clear them; an actively storming queue is left untouched (and reported as skipped) until the storm ends.

Previous command output (if the output of a command-line utility has changed)

admin@sonic:~$ show pfcwd stats
        QUEUE       STATUS    STORM DETECTED/RESTORED    TX OK/DROP    RX OK/DROP    TX LAST OK/DROP    RX LAST OK/DROP
-------------  -----------  -------------------------  ------------  ------------  -----------------  -----------------
Ethernet192:3  operational                        1/1           0/0           0/0                0/0                0/0

New command output (if the output of a command-line utility has changed)

admin@sonic:~$ sonic-clear pfcwdstats
PFC Watchdog counters cleared.

admin@sonic:~$ show pfcwd stats
  QUEUE    STATUS    STORM DETECTED/RESTORED    TX OK/DROP    RX OK/DROP    TX LAST OK/DROP    RX LAST OK/DROP
-------  --------  -------------------------  ------------  ------------  -----------------  -----------------

Which release branch to backport (provide reason below if selected)

  • 201811
  • 201911
  • 202012
  • 202205
  • 202305
  • 202311
  • 202405
  • 202411
  • 202505
  • 202511
  • 202605

There is currently no CLI to clear PFC watchdog statistics. Clearing them is
needed when troubleshooting PFC storms, where stale counts from a prior event
make it hard to tell whether a storm is ongoing.

This adds:

- scripts/pfcwdstat: a new tool that zeroes the PFC_WD_QUEUE_STATS_* fields in
  COUNTERS_DB, following the standard counter-clear pattern (pfcstat -c,
  queuestat -c, ...). It enumerates queues via COUNTERS_QUEUE_NAME_MAP -- the
  same source 'show pfcwd stats' uses -- so stale stats from queues that are no
  longer actively monitored (STATUS=N/A) are also cleared.
- Queues with an active storm (PFC_WD_STATUS == 'stormed') are skipped, so the
  in-flight DEADLOCK_DETECTED/RESTORED pair is not split (which would otherwise
  leave RESTORED > DETECTED once the storm ends).
- clear/main.py: 'sonic-clear pfcwdstats', invoking 'pfcwdstat -c'.
- setup.py: install scripts/pfcwdstat.
- tests for the clear command and the pfcwdstat clear logic.

Signed-off-by: Pinky Agrawal <pinky@nexthop.ai>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@mssonicbld

Copy link
Copy Markdown
Collaborator

Hi, there are workflow run(s) waiting for approval, you may be first-time contributor. I will notify maintainers to help approve once PR is approved. Thanks!

---Powered by SONiC BuildBot

@mssonicbld

Copy link
Copy Markdown
Collaborator

This PR has backport request for branch(es): 202605.
Added label(s) for branch(es) 202605.

---Powered by SONiC BuildBot

Comment thread scripts/pfcwdstat

Queues with an active storm (PFC_WD_STATUS == 'stormed') are skipped.
"""
db = SonicV2Connector()

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.

sonicV2connector() handles only global namespace and does not work in multi asic. Please add support for multi-asic also

Comment thread scripts/pfcwdstat
db = SonicV2Connector()
db.connect(db.COUNTERS_DB)

queue_name_map = db.get_all(db.COUNTERS_DB, 'COUNTERS_QUEUE_NAME_MAP')

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.

Usually all the clear commands take the snapshot of the stats from COUNTER_DB and saves it in /tmp/cache . Then show commands shows the diff between stats COUNTER_DB and /tmp/cache. Why are you clearing it from COUNTER_DB. Is this the requirement?

Comment thread clear/main.py

@cli.command()
def pfcwdstats():
"""Clear PFC Watchdog stats counters"""

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.

Please update doc/Command-Reference.md

Comment thread scripts/pfcwdstat
skipped.append(queue_name)
continue
for field in PFC_WD_STATS_FIELDS:
db.set(db.COUNTERS_DB, counter_key, field, '0')

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.

Even if you have to clear from COUNTERS_DB, can't you use hmset and clear all stats at once instead of clearing 1 by 1

@vmittal-msft vmittal-msft left a comment

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.

Thanks for the PR! I reviewed the change end-to-end against the current sources. It works on a single-ASIC box, but two items I'd treat as blocking:

  1. No multi-ASIC / chassis supportSonicV2Connector() only touches the global DB, so nothing is cleared on multi-ASIC while show pfcwd stats still shows counts.
  2. Destructive COUNTERS_DB mutation — every sibling clear command uses the non-destructive UserCache snapshot+diff pattern instead of writing into the shared counters DB.

Plus a doc/Command-Reference.md update. Details inline — these corroborate and extend @saksarav-nokia's review. Nice touch skipping actively-stormed queues to keep the DEADLOCK_DETECTED/RESTORED pair intact.

Comment thread scripts/pfcwdstat

Queues with an active storm (PFC_WD_STATUS == 'stormed') are skipped.
"""
db = SonicV2Connector()

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.

Multi-ASIC: this won't clear anything on a multi-ASIC/VOQ chassis (+1 to @saksarav-nokia, confirming it's a functional gap, not style).

SonicV2Connector() with no namespace binds only to the global DB. But the reader show pfcwd stats (pfcwd/main.py) walks each ASIC via the @multi_asic_util.run_on_multi_asic decorator, and the sibling clear tools (pfcstat, queuestat) and even pg-drop -c clear all iterate multi_asic.get_namespace_list().

So on a multi-ASIC box, COUNTERS_QUEUE_NAME_MAP in the global DB is empty → this prints No PFC Watchdog stats found. and clears nothing, while show pfcwd stats still shows per-ASIC counts. Please wrap clear_stats() in a namespace loop (MultiAsic / run_on_multi_asic) or add -n/--namespace like pg-drop.

Comment thread scripts/pfcwdstat
skipped.append(queue_name)
continue
for field in PFC_WD_STATS_FIELDS:
db.set(db.COUNTERS_DB, counter_key, field, '0')

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.

Directly zeroing COUNTERS_DB diverges from the standard clear pattern (this is the crux of @saksarav-nokia's question).

Every other stats-clear in this repo is non-destructive: pfcstat -c, queuestat -c, portstat -c, and pg-drop -c clear snapshot COUNTERS_DB into UserCache (/tmp/...) and the show command renders current - cached. They never mutate COUNTERS_DB.

Writing '0' straight into the shared COUNTERS_DB is a different contract: any other consumer of these counters (telemetry / gNMI streaming, rate calculators) will observe a reset / negative delta, and the clear is global + irreversible rather than per-user. It only works here because you skip stormed queues (no active producer to overwrite the zeros).

Preferred: the cache+diff approach (which also means teaching show pfcwd stats to subtract the baseline). If a hard reset is genuinely required, please call that out and justify it in the PR description.

Minor (also @saksarav-nokia): if you keep the DB write, one hmset/pipeline per queue avoids the per-field round-trips.

Comment thread scripts/pfcwdstat
"""

import argparse
import sys

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.

Nit: sys is imported but unused (F401). Also clear_stats (L27), main (L69), and the __main__ guard (L82) are separated by a single blank line — PEP8 wants two (E302/E305).

Heads-up: the repo's pre-commit runs flake8==4.0.1 in --diff mode, which does not flag these on a brand-new file (I reproduced it locally — that's why the Static Analysis check is green), so they'll silently slip through unless cleaned up by hand.

Comment thread clear/main.py


@cli.command()
def pfcwdstats():

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.

+1 to @saksarav-nokia on docs. Please add sonic-clear pfcwdstats to doc/Command-Reference.md — there's already a show pfcwd stats section and a NOTE: PFC counters ... sonic-clear pfccounters blurb, so a parallel note under the PFC watchdog section keeps the new command discoverable.

Comment thread tests/pfcwd_test.py
importlib.reload(pfcwd.main)


class TestPfcwdstatClear(object):

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.

These tests fully mock SonicV2Connector, so they pass regardless of the multi-ASIC gap flagged in scripts/pfcwdstat — a single mocked DB hides the fact that only the global namespace is cleared.

Once namespace handling is added, please add a multi-ASIC case (e.g. UTILITIES_UNIT_TESTING_TOPOLOGY=multi_asic with per-namespace mock DBs) asserting each namespace's counters are cleared. Tests for the -c arg path in main() and for the Skipped queue(s) ... / No PFC Watchdog stats found. output would also lock in the behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants