Skip to content
Open
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3324,7 +3324,8 @@ def stop(verbose):

@pfcwd.command()
@click.option('--verbose', is_flag=True, help="Enable verbose output")
@click.argument('poll_interval', type=click.IntRange(100, 3000))
# Keep in sync with the pfcwd CLI validation and sonic-pfcwd YANG model.
@click.argument('poll_interval', type=click.IntRange(100, 1000))
def interval(poll_interval, verbose):
""" Set PFC watchdog counter polling interval (ms) """

Expand Down
12 changes: 9 additions & 3 deletions pfcwd/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
pass

# Default configuration
MAX_POLL_INTERVAL_TIME = 1000
DEFAULT_DETECTION_TIME = 200
DEFAULT_RESTORATION_TIME = 200
DEFAULT_POLL_INTERVAL = 200
Expand Down Expand Up @@ -344,7 +345,7 @@ def interval(self, poll_interval):
pfcwd_info = {}
if poll_interval is not None:
pfcwd_table = self.config_db.get_table(CONFIG_DB_PFC_WD_TABLE_NAME)
entry_min = 3000
entry_min = MAX_POLL_INTERVAL_TIME
for entry in pfcwd_table:
if("Ethernet" not in entry):
continue
Expand Down Expand Up @@ -418,6 +419,11 @@ def start_default(self):

# Paramter values positively correlate to the number of ports.
multiply = max(1, (port_num-1)//DEFAULT_PORT_NUM+1)

pfc_wd_poll_interval_time = DEFAULT_POLL_INTERVAL * multiply
if pfc_wd_poll_interval_time > MAX_POLL_INTERVAL_TIME:
pfc_wd_poll_interval_time = MAX_POLL_INTERVAL_TIME

pfcwd_info = {
'detection_time': DEFAULT_DETECTION_TIME * multiply,
'restoration_time': DEFAULT_RESTORATION_TIME * multiply,
Expand All @@ -429,7 +435,7 @@ def start_default(self):
self.verify_pfc_enable_status_per_port(port, pfcwd_info, overwrite=True)

pfcwd_info = {}
pfcwd_info['POLL_INTERVAL'] = DEFAULT_POLL_INTERVAL * multiply
pfcwd_info['POLL_INTERVAL'] = pfc_wd_poll_interval_time
self.config_db.mod_entry(
CONFIG_DB_PFC_WD_TABLE_NAME, "GLOBAL", pfcwd_info
)
Expand Down Expand Up @@ -521,7 +527,7 @@ def start(db, action, restoration_time, ports, detection_time, pfc_stat_history)
# Set WD poll interval
class Interval(object):
@cli.command()
@click.argument('poll_interval', type=click.IntRange(100, 3000))
@click.argument('poll_interval', type=click.IntRange(100, MAX_POLL_INTERVAL_TIME))
@clicommon.pass_db
def interval(db, poll_interval):
""" Set PFC watchdog counter polling interval """
Expand Down
20 changes: 20 additions & 0 deletions tests/pfcwd_input/pfcwd_test_vectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,26 @@
Ethernet8 drop 600 600 disable
"""

# 32-port system: multiply=1, detection/restoration=200, poll=200ms (same as default)
pfcwd_show_start_default_32_ports = """\
Changed polling interval to 200ms
PORT ACTION DETECTION TIME RESTORATION TIME HISTORY
--------- -------- ---------------- ------------------ ---------
Ethernet0 drop 200 200 disable
Ethernet4 drop 200 200 disable
Ethernet8 drop 600 600 disable
"""

# 512-port system: multiply=16, detection/restoration=3200, poll capped at 1000ms
pfcwd_show_start_default_512_ports = """\
Changed polling interval to 1000ms
PORT ACTION DETECTION TIME RESTORATION TIME HISTORY
--------- -------- ---------------- ------------------ ---------
Ethernet0 drop 3200 3200 disable
Ethernet4 drop 3200 3200 disable
Ethernet8 drop 600 600 disable
"""

pfcwd_show_start_history_output = """\
Changed polling interval to 600ms
PORT ACTION DETECTION TIME RESTORATION TIME HISTORY
Expand Down
62 changes: 62 additions & 0 deletions tests/pfcwd_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,68 @@ def test_pfcwd_start_actions(self, mock_os):
assert result.exit_code == 0
assert result.output == test_vectors.pfcwd_show_start_default

@patch('pfcwd.main.os')
def test_pfcwd_start_default_32_ports(self, mock_os):
"""Test start_default on 32-port system: multiply=1, detection/restoration=200, poll=200ms"""
import pfcwd.main as pfcwd
runner = CliRunner()
db = Db()

# Patch PORT table to have exactly 32 ports so multiply = (32-1)//32+1 = 1
original_get_table = db.cfgdb.get_table

def mock_get_table_32_ports(table):
if table == 'PORT':
return {'Ethernet%d' % i: {} for i in range(0, 32 * 4, 4)} # 32 ports
return original_get_table(table)

mock_os.geteuid.return_value = 0
with patch.object(db.cfgdb, 'get_table', side_effect=mock_get_table_32_ports):
result = runner.invoke(
pfcwd.cli.commands["start_default"],
[],
obj=db
)
assert result.exit_code == 0

result = runner.invoke(
pfcwd.cli.commands["show"].commands["config"],
obj=db
)
assert result.exit_code == 0
assert result.output == test_vectors.pfcwd_show_start_default_32_ports

@patch('pfcwd.main.os')
def test_pfcwd_start_default_512_ports(self, mock_os):
"""Test start_default on 512-port system: multiply=16, detection/restoration=3200, poll=1000ms"""
import pfcwd.main as pfcwd
runner = CliRunner()
db = Db()

# Patch PORT table to have 512 ports so multiply = (512-1)//32+1 = 16
original_get_table = db.cfgdb.get_table

def mock_get_table_512_ports(table):
if table == 'PORT':
return {'Ethernet%d' % i: {} for i in range(512)}
return original_get_table(table)

mock_os.geteuid.return_value = 0
with patch.object(db.cfgdb, 'get_table', side_effect=mock_get_table_512_ports):
result = runner.invoke(
pfcwd.cli.commands["start_default"],
[],
obj=db
)
assert result.exit_code == 0

result = runner.invoke(
pfcwd.cli.commands["show"].commands["config"],
obj=db
)
assert result.exit_code == 0
assert result.output == test_vectors.pfcwd_show_start_default_512_ports

@patch('pfcwd.main.os')
def test_pfcwd_start_history(self, mock_os):
# pfcwd start all 600 --restoration-time 601 --pfc-stat-history
Expand Down
Loading