Skip to content
Merged
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
60 changes: 43 additions & 17 deletions show/vnet.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import ipaddress
import shutil

import click
import utilities_common.cli as clicommon
from natsort import natsorted
from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector
from tabulate import tabulate
import ipaddress

from sonic_py_common import multi_asic
import utilities_common.cli as clicommon
import utilities_common.multi_asic as multi_asic_util

#
# 'vnet' command ("show vnet")
Expand Down Expand Up @@ -442,31 +447,45 @@ def routes():
pass


def _ecmp_row_width(max_item_len, num_wrap_cols, fixed_cols_est):
"""Compute how many ECMP items fit per row to stay within the current terminal width.

:param max_item_len: length of the longest individual item string
:param num_wrap_cols: number of columns that wrap (2 for nexthop+interface,
3 for endpoint+mac+vni)
:param fixed_cols_est: estimated width of non-wrapping column content plus all
inter-column tabulate spacing (2 spaces × (ncols-1))
"""
if max_item_len <= 0:
return 1
terminal_cols = shutil.get_terminal_size((80, 24)).columns
row_width = (terminal_cols - fixed_cols_est) // (num_wrap_cols * (max_item_len + 1))
return max(1, row_width)


def pretty_print_local(table, r, nexthop_val, ifname_val):
nexthops = [nexthop.strip() for nexthop in nexthop_val.split(',')] if nexthop_val else []
nexthops = [nexthop.strip() for nexthop in nexthop_val.split(',')] if nexthop_val else [""]
interfaces = [interface.strip() for interface in ifname_val.split(',')] if ifname_val else []
if not nexthops:
nexthops = [""]

all_items = list(nexthops) + list(interfaces)
max_len = max((len(item) for item in all_items), default=0)
row_width = 2 if max_len > 15 else 3
# route_header: ['vnet name', 'prefix', 'nexthop', 'interface']
# fixed_cols_est = vnet_name(~15) + prefix(~18) + 4-col spacing(6) = 39
# cap at 2 so nexthop/interface columns stay readable on any terminal width
row_width = min(2, _ecmp_row_width(max_len, num_wrap_cols=2, fixed_cols_est=39))

max_entries = max(len(nexthops), len(interfaces))
i = 0
while i < max_entries:
r.append(",".join(nexthops[i:i + row_width]) if i < len(nexthops) else "")
if interfaces:
r.append(",".join(interfaces[i:i + row_width]) if i < len(interfaces) else "")
else:
r.append(ifname_val if i == 0 else "")
r.append(",".join(interfaces[i:i + row_width]) if i < len(interfaces) else "")
i += row_width
table.append(r)
r = ["", ""]


def pretty_print(table, r, epval, mac_addr, vni, metric, state):
endpoints = epval.split(',')
def pretty_print_tunnel(table, r, epval, mac_addr, vni, metric, state):
endpoints = epval.split(',') if epval else [""]
# When mac_address or vni is a per-endpoint list, split so all three fields
# wrap in the same chunks, keeps rows aligned at any ECMP scale.
macs = mac_addr.split(',') if mac_addr and ',' in mac_addr else None
Expand All @@ -480,7 +499,9 @@ def pretty_print(table, r, epval, mac_addr, vni, metric, state):
if vnis:
all_items.extend(vnis)
max_len = max((len(item) for item in all_items), default=0)
row_width = 2 if max_len > 15 else 3
# tunnel_header: ['vnet name', 'prefix', 'endpoint', 'mac address', 'vni', 'metric', 'status']
# fixed_cols_est = vnet_name(~15) + prefix(~16) + metric(6) + status(6) + 7-col spacing(12) = 55
row_width = _ecmp_row_width(max_len, num_wrap_cols=3, fixed_cols_est=55)

i = 0
while i < len(endpoints):
Expand Down Expand Up @@ -579,13 +600,18 @@ def _show_tunnel_helper(vnet_name=None, appl_db=None, state_db=None):
r.extend(k.split(":", 2)[1:])
state_db_key = '|'.join(k.split(":", 2))
val = appl_db.get_all(appl_db.APPL_DB, k)
if not val:
continue
val_state = state_db.get_all(state_db.STATE_DB, state_db_key)
epval = val.get('endpoint')
mac_addr = val.get('mac_address') or ''
vni = val.get('vni') or ''
state = val_state.get('state') if val_state else ""
raw_metric = val.get('metric')
metric = int(raw_metric) if raw_metric else ''
pretty_print(table, r, epval,
val.get('mac_address') or '', val.get('vni') or '',
metric, state)
try:
metric = int(raw_metric) if raw_metric else ''
except (ValueError, TypeError):
metric = raw_metric
pretty_print_tunnel(table, r, epval, mac_addr, vni, metric, state)

click.echo(tabulate(table, tunnel_header))
Loading
Loading