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
34 changes: 28 additions & 6 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -5966,17 +5966,39 @@ The show interfaces flap command provides detailed insights into interface event

- Usage:
```
show interfaces flap
show interfaces flap [OPTIONS] [<interfacename>]

Options:
-d, --display [all|frontend] Show internal interfaces [default: frontend]
-n, --namespace <namespace> Namespace name or all
-?, -h, --help Show this message and exit.
```
- Example:
```
admin@sonic:~$ show interfaces flap
Interface Flap Count Admin Oper Link Down TimeStamp (UTC) Link Up TimeStamp (UTC)
----------- ------------ ------- ------ -------------------------------------------------------- -----------------------------------------------------------
Ethernet0 5 Up Up Last flapped : 2024-10-01 10:00:00 (0 days 00:01:23 ago) Last Link up: 2024-09-30 10:01:03 UTC (1 days 02:30:15 ago)
Ethernet4 Never Up Up Never Last Link up: 2024-09-30 10:01:03 UTC (1 days 02:30:15 ago)
Ethernet8 1 Up Up Last flapped : 2024-10-01 10:01:00 (0 days 00:00:23 ago) Last Link up: 2024-10-02 10:01:03 UTC (5 days 02:30:15 ago)
Interface Flap Count Admin Oper Link Down TimeStamp(UTC) Link Up TimeStamp(UTC)
----------- ------------ ------- ------ -------------------------- ------------------------
Ethernet0 4097 Up Up Sat Feb 21 11:00:41 2026 Sat Feb 21 11:00:59 2026
Ethernet8 4035 Up Up Sat Feb 21 11:00:41 2026 Sat Feb 21 11:00:59 2026
Ethernet16 4015 Up Up Sat Feb 21 11:01:23 2026 Sat Feb 21 11:01:41 2026
```
- Example (to display interface on multi-ASIC platform):
```
admin@sonic:~$ show interfaces flap Ethernet0
Interface Flap Count Admin Oper Link Down TimeStamp(UTC) Link Up TimeStamp(UTC)
----------- ------------ ------- ------ -------------------------- ------------------------
Ethernet0 4097 Up Up Sat Feb 21 11:00:41 2026 Sat Feb 21 11:00:59 2026
```
- Example (to display interfaces for specific ASIC on multi-ASIC platform):
```
admin@sonic:~$ show interfaces flap -n asic1
Interface Flap Count Admin Oper Link Down TimeStamp(UTC) Link Up TimeStamp(UTC)
----------- ------------ ------- ------ -------------------------- ------------------------
Ethernet144 10 Up Down Wed Feb 18 20:55:09 2026 Wed Feb 18 20:53:02 2026
Ethernet152 14 Up Down Wed Feb 18 21:01:39 2026 Wed Feb 18 21:00:32 2026
Ethernet160 10 Up Down Wed Feb 18 21:04:36 2026 Wed Feb 18 21:01:58 2026
```

**show interfaces errors**

The show interface errors command provides detailed statistics and error counters for MAC-level operations on an interface. It displays the status of various operational parameters, error counts, and timestamps for when these errors occurred.
Expand Down
77 changes: 45 additions & 32 deletions show/interfaces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,24 +449,21 @@ def mpls(ctx, interfacename, namespace, display):
interfaces.add_command(portchannel.portchannel)



@interfaces.command()
@click.argument('interfacename', required=False)
@multi_asic_util.multi_asic_click_options
@click.pass_context
def flap(ctx, interfacename):
def flap(ctx, interfacename, namespace, display):
"""Show Interface Flap Information <interfacename>"""

namespace = '' # Default namespace
port_dict = multi_asic.get_port_table(namespace=namespace)
if interfacename:
display = constants.DISPLAY_ALL

masic = multi_asic_util.MultiAsic(display_option=display, namespace_option=namespace)
ns_list = masic.get_ns_list_based_on_options()

# If interfacename is given, validate it
if interfacename:
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)
if interfacename not in port_dict:
ctx.fail("Invalid interface name {}".format(interfacename))

db = SonicV2Connector(host=REDIS_HOSTIP)
db.connect(db.APPL_DB)

# Prepare the table headers and body
header = [
Expand All @@ -478,41 +475,57 @@ def flap(ctx, interfacename):
'Link Up TimeStamp(UTC)'
]
body = []
intf_found = False

for ns in ns_list:
masic.current_namespace = ns
appl_db = multi_asic.connect_to_all_dbs_for_ns(namespace=ns)
port_dict = multi_asic.get_port_table(namespace=ns)

# Loop through all ports or the specified port
ports = [interfacename] if interfacename else natsorted(list(port_dict.keys()))

# Loop through all ports or the specified port
ports = [interfacename] if interfacename else natsorted(list(port_dict.keys()))
for port in ports:
if port not in port_dict:
continue

for port in ports:
port_data = db.get_all(db.APPL_DB, f'PORT_TABLE:{port}') or {}
# Skip internal ports based on display option
if masic.skip_display(constants.PORT_OBJ, port):
continue
if interfacename and port == interfacename:
intf_found = True
port_data = appl_db.get_all(appl_db.APPL_DB, f'PORT_TABLE:{port}') or {}

flap_count = port_data.get('flap_count', 'Never')
admin_status = port_data.get('admin_status', 'Unknown').capitalize()
oper_status = port_data.get('oper_status', 'Unknown').capitalize()
flap_count = port_data.get('flap_count', 'Never')
admin_status = port_data.get('admin_status', 'Unknown').capitalize()
oper_status = port_data.get('oper_status', 'Unknown').capitalize()

# Get timestamps and convert them to UTC format if possible
last_up_time = port_data.get('last_up_time', 'Never')
last_down_time = port_data.get('last_down_time', 'Never')
# Get timestamps and convert them to UTC format if possible
last_up_time = port_data.get('last_up_time', 'Never')
last_down_time = port_data.get('last_down_time', 'Never')

# Format output row
row = [
port,
flap_count,
admin_status,
oper_status,
f"{last_down_time}" if last_down_time != 'Never' else 'Never',
f"{last_up_time}" if last_up_time != 'Never' else 'Never'
]
# Format output row
row = [
port,
flap_count,
admin_status,
oper_status,
last_down_time,
last_up_time
]

body.append(row)
body.append(row)

# Validate interface name after checking all namespaces
if interfacename and not intf_found:
ctx.fail("Invalid interface name {}".format(interfacename))

# Sort the body by interface name for consistent display
body = natsorted(body, key=lambda x: x[0])

# Display the formatted table
click.echo(tabulate(body, header))

Copy link
Contributor

Choose a reason for hiding this comment

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

@pnakka28 db connection does not need to be closed at the end?

db.close(db.APPL_DB)


def get_all_port_errors(interfacename):

Expand Down
106 changes: 106 additions & 0 deletions tests/flap_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import os
import importlib

from click.testing import CliRunner

import show.main as show

intf_flap_masic_expected_output_default = """\
Interface Flap Count Admin Oper Link Down TimeStamp(UTC) Link Up TimeStamp(UTC)
----------- ------------ ------- ------- -------------------------- ------------------------
Ethernet0 5 Up Up Sat Jan 17 00:04:42 2025 Sat Jan 18 00:08:42 2025
Ethernet4 Never Up Up Never Never
Ethernet16 Never Unknown Unknown Never Never
"""

# Display all: all namespaces (asic0 + asic1) including backplane ports
intf_flap_masic_expected_output_display_all = """\
Interface Flap Count Admin Oper Link Down TimeStamp(UTC) Link Up TimeStamp(UTC)
-------------- ------------ ------- ------- -------------------------- ------------------------
Ethernet0 5 Up Up Sat Jan 17 00:04:42 2025 Sat Jan 18 00:08:42 2025
Ethernet4 Never Up Up Never Never
Ethernet16 Never Unknown Unknown Never Never
Ethernet64 2 Up Up Thu Feb 12 23:03:40 2026 Thu Feb 12 23:25:31 2026
Ethernet-BP0 Never Up Up Never Never
Ethernet-BP4 Never Up Up Never Never
Ethernet-BP256 Never Up Up Never Never
Ethernet-BP260 Never Up Up Never Never
"""

intf_flap_masic_expected_output_ethernet0 = """\
Interface Flap Count Admin Oper Link Down TimeStamp(UTC) Link Up TimeStamp(UTC)
----------- ------------ ------- ------ -------------------------- ------------------------
Ethernet0 5 Up Up Sat Jan 17 00:04:42 2025 Sat Jan 18 00:08:42 2025
"""

intf_flap_masic_expected_output_ethernet64 = """\
Interface Flap Count Admin Oper Link Down TimeStamp(UTC) Link Up TimeStamp(UTC)
----------- ------------ ------- ------ -------------------------- ------------------------
Ethernet64 2 Up Up Thu Feb 12 23:03:40 2026 Thu Feb 12 23:25:31 2026
"""


class TestInterfacesFlapMasic(object):
"""Test cases for 'show interfaces flap' on multi-ASIC platforms."""

@classmethod
def setup_class(cls):
print("SETUP")
from .mock_tables import mock_multi_asic
importlib.reload(mock_multi_asic)
from .mock_tables import dbconnector
dbconnector.load_namespace_config()

def test_show_interfaces_flap_masic_default(self):
"""Test frontend display shows only front-panel namespace ports."""
runner = CliRunner()
result = runner.invoke(
show.cli.commands["interfaces"].commands["flap"],
["-d", "frontend"])
assert result.exit_code == 0
assert result.output == intf_flap_masic_expected_output_default

def test_show_interfaces_flap_masic_display_all(self):
"""Test -d all shows all namespaces including backplane ports."""
runner = CliRunner()
result = runner.invoke(
show.cli.commands["interfaces"].commands["flap"],
["-d", "all"])
assert result.exit_code == 0
assert result.output == intf_flap_masic_expected_output_display_all

def test_show_interfaces_flap_masic_ethernet0(self):
"""Test specific port lookup on asic0 returns correct flap data."""
runner = CliRunner()
result = runner.invoke(
show.cli.commands["interfaces"].commands["flap"],
["Ethernet0"])
assert result.exit_code == 0
assert result.output == intf_flap_masic_expected_output_ethernet0

def test_show_interfaces_flap_masic_ethernet64(self):
"""Test specific port lookup on asic1 returns correct flap data."""
runner = CliRunner()
result = runner.invoke(
show.cli.commands["interfaces"].commands["flap"],
["Ethernet64"])
assert result.exit_code == 0
assert result.output == intf_flap_masic_expected_output_ethernet64

def test_show_interfaces_flap_masic_invalid_interface(self):
"""Test invalid interface name fails."""
runner = CliRunner()
result = runner.invoke(
show.cli.commands["interfaces"].commands["flap"],
["Ethernet100"])
assert result.exit_code != 0
assert "Invalid interface name" in result.output

@classmethod
def teardown_class(cls):
print("TEARDOWN")
os.environ['UTILITIES_UNIT_TESTING'] = "0"
from .mock_tables import mock_single_asic
importlib.reload(mock_single_asic)
from .mock_tables import dbconnector
dbconnector.load_database_config()
5 changes: 4 additions & 1 deletion tests/mock_tables/asic0/appl_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
"admin_status": "up",
"role": "Ext",
"speed": "40000",
"asic_port_name": "Eth0-ASIC0"
"asic_port_name": "Eth0-ASIC0",
"flap_count": "5",
"last_down_time": "Sat Jan 17 00:04:42 2025",
"last_up_time": "Sat Jan 18 00:08:42 2025"
},
"PORT_TABLE:Ethernet4": {
"oper_status": "up",
Expand Down
5 changes: 4 additions & 1 deletion tests/mock_tables/asic1/appl_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
"admin_status": "up",
"role": "Ext",
"speed": "40000",
"asic_port_name": "Eth0-ASIC1"
"asic_port_name": "Eth0-ASIC1",
"flap_count": "2",
"last_down_time": "Thu Feb 12 23:03:40 2026",
"last_up_time": "Thu Feb 12 23:25:31 2026"
},
"PORT_TABLE:Ethernet-BP256": {
"oper_status": "up",
Expand Down
Loading