diff options
| author | Christian Breunig <christian@breunig.cc> | 2026-03-19 19:50:37 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-19 19:50:37 +0100 |
| commit | fc06cc45148a42171baf9f4ae01da33c3f0df1aa (patch) | |
| tree | 11eaf65a8a5b73dd3e736201599b3f388aeab725 /src | |
| parent | 7957857e6b5d6572d2c9831e0e66dac80e7a415e (diff) | |
| parent | 8d1dd6f610fa10d8ba9da03749da67bdd0717b17 (diff) | |
| download | vyos-1x-fc06cc45148a42171baf9f4ae01da33c3f0df1aa.tar.gz vyos-1x-fc06cc45148a42171baf9f4ae01da33c3f0df1aa.zip | |
Merge pull request #5064 from natali-rs1985/T8352
T8352: VPP add op-mode commands to show bonding interfaces
Diffstat (limited to 'src')
| -rw-r--r-- | src/conf_mode/vpp_interfaces_bonding.py | 2 | ||||
| -rwxr-xr-x | src/op_mode/vpp.py | 95 |
2 files changed, 93 insertions, 4 deletions
diff --git a/src/conf_mode/vpp_interfaces_bonding.py b/src/conf_mode/vpp_interfaces_bonding.py index 8d9930a20..fa49f2da5 100644 --- a/src/conf_mode/vpp_interfaces_bonding.py +++ b/src/conf_mode/vpp_interfaces_bonding.py @@ -53,7 +53,7 @@ def _get_bond_lb(lb_name: str) -> int: 'layer3+4': 1, } - return lb_mapping.get(lb_name, 5) + return lb_mapping.get(lb_name, 0) def get_config(config=None) -> dict: diff --git a/src/op_mode/vpp.py b/src/op_mode/vpp.py index 503e2fccc..0cdb94e3a 100755 --- a/src/op_mode/vpp.py +++ b/src/op_mode/vpp.py @@ -20,6 +20,7 @@ import typing from tabulate import tabulate from vyos.vpp import VPPControl +from vyos.vpp.utils import vpp_iface_name_transform from vyos.configquery import ConfigTreeQuery import vyos.opmode @@ -42,6 +43,21 @@ class VPPShow: 3: 'COLLECTING_DISTRIBUTING', } PTX_STATES = {0: 'NO_PERIODIC', 1: 'FAST', 2: 'SLOW', 3: 'PERIODIC_TX'} + BOND_MODE = { + 1: 'round-robin', + 2: 'active-backup', + 3: 'xor', + 4: 'broadcast', + 5: 'lacp', + } + BOND_LB = { + 0: 'layer2', + 1: 'layer3+4', + 2: 'layer2+3', + 3: 'round-robin', + 4: 'broadcast', + 5: 'active-backup', + } def __init__(self): self.config = ConfigTreeQuery() @@ -159,7 +175,7 @@ class VPPShow: return data if raw else self._show_ipfix_table_formatted() # ----------------------------- - # LACP information + # Bonding information # ----------------------------- def _get_raw_output(self, data_dump: typing.List[dict]) -> list[dict]: data = [json.loads(json.dumps(d._asdict(), default=str)) for d in data_dump] @@ -226,6 +242,47 @@ class VPPShow: f'PTX-state: {self.PTX_STATES[d["ptx_state"]]}' ) + def _get_bond_raw(self, index: typing.Optional[str]) -> list[dict]: + bond_dump = self.vpp.api.sw_bond_interface_dump(sw_if_index=index) + + result = [] + for bond in bond_dump: + bond_info = { + 'interface_name': bond.interface_name, + 'sw_if_index': bond.sw_if_index, + 'mode': self.BOND_MODE[bond.mode], + 'hash_policy': self.BOND_LB[bond.lb], + 'active_members': bond.active_members, + 'members': {}, + } + members = self.vpp.api.sw_member_interface_dump( + sw_if_index=bond.sw_if_index + ) + for member in members: + bond_info['members'][member.interface_name] = { + 'sw_if_index': member.sw_if_index, + 'is_passive': member.is_passive, + 'is_long_timeout': member.is_long_timeout, + 'is_local_numa': member.is_local_numa, + 'weight': member.weight, + } + result.append(bond_info) + + return result + + def _show_bond_info_formatted(self, data: typing.List[dict]) -> str: + table_data = [ + { + 'Interface': d['interface_name'], + 'Mode': d['mode'], + 'Hash': d['hash_policy'], + 'Members': '\n'.join(sorted(d['members'].keys())), + 'Active members': d['active_members'], + } + for d in data + ] + return tabulate(table_data, headers='keys', tablefmt='simple', numalign='left') + def lacp_info(self, raw: bool, ifname: typing.Optional[str]): data = self._get_lacp_raw(ifname) @@ -252,6 +309,31 @@ class VPPShow: return data.reply + def bond_info(self, raw: bool, ifname: typing.Optional[str]) -> str: + index = NO_INDEX + if ifname: + if not ifname.startswith('vppbond') or not ifname[7:].isdigit(): + raise vyos.opmode.IncorrectValue( + f'"{ifname}" is not a valid bonding interface name (expected vppbondN)' + ) + + ifname_vpp = vpp_iface_name_transform(ifname) + index = self.vpp.get_sw_if_index(ifname_vpp) + if index is None: + raise vyos.opmode.IncorrectValue( + f'Bonding interface {ifname} does not exist in VPP' + ) + + data = self._get_bond_raw(index) + + return data if raw else self._show_bond_info_formatted(data) + + def bond_details(self, raw: bool) -> str: + # VPP API call is not so informative -> use CLI command + cmd_command = 'show bond details' + data = self.vpp.cli_cmd(cmd_command) + return [data.reply] if raw else data.reply + # ----------------------------- # Bridge-domain information # ----------------------------- @@ -343,7 +425,6 @@ class VPPShow: cmd_command = f'show bridge-domain {bd_id} detail' data = self.vpp.cli_cmd(cmd_command) - if raw: return [data.reply] @@ -390,7 +471,7 @@ def show_ipfix_table(raw: bool): return VPPShow().ipfix_table(raw) # ----------------------------- -# VPP LACP information +# VPP Bonding information # ----------------------------- @vyos.opmode.verify_cli_exists(['interfaces', 'vpp', 'bonding']) def show_lacp(raw: bool, ifname: typing.Optional[str]): @@ -400,6 +481,14 @@ def show_lacp(raw: bool, ifname: typing.Optional[str]): def show_lacp_details(raw: bool, ifname: typing.Optional[str]): return VPPShow().lacp_details(raw, ifname) +@vyos.opmode.verify_cli_exists(['interfaces', 'vpp', 'bonding']) +def show_bond(raw: bool, ifname: typing.Optional[str]): + return VPPShow().bond_info(raw, ifname) + +@vyos.opmode.verify_cli_exists(['interfaces', 'vpp', 'bonding']) +def show_bond_details(raw: bool): + return VPPShow().bond_details(raw) + # ----------------------------- # Bridge op-mode entrie # ----------------------------- |
