Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

T6291: Add LACP related op commands (backport #3389) #3406

Merged
merged 1 commit into from
May 4, 2024
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
34 changes: 33 additions & 1 deletion op-mode-definitions/show-interfaces-bonding.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,27 @@
<properties>
<help>Show detailed interface information</help>
</properties>
<command>if [ -f "/proc/net/bonding/$4" ]; then cat "/proc/net/bonding/$4"; else echo "Interface $4 does not exist!"; fi</command>
<command>if [ -f "/proc/net/bonding/$4" ]; then sudo cat "/proc/net/bonding/$4"; else echo "Interface $4 does not exist!"; fi</command>
</leafNode>
<node name="lacp">
<properties>
<help>Show LACP related info</help>
</properties>
<children>
<leafNode name="detail">
<properties>
<help>Show LACP details</help>
</properties>
<command>sudo ${vyos_op_scripts_dir}/bonding.py show_lacp_detail --interface="$4" </command>
</leafNode>
<leafNode name="neighbors">
<properties>
<help>Show LACP Neighbors</help>
</properties>
<command>sudo ${vyos_op_scripts_dir}/bonding.py show_lacp_neighbors --interface="$4"</command>
</leafNode>
</children>
</node>
<leafNode name="slaves">
<properties>
<help>Show specified bonding interface information</help>
Expand Down Expand Up @@ -62,6 +81,19 @@
</properties>
<command>${vyos_op_scripts_dir}/interfaces.py show --intf-type=bonding</command>
</leafNode>
<node name="lacp">
<properties>
<help>Show LACP related info</help>
</properties>
<children>
<leafNode name="detail">
<properties>
<help>Show LACP details</help>
</properties>
<command>sudo ${vyos_op_scripts_dir}/bonding.py show_lacp_detail</command>
</leafNode>
</children>
</node>
<leafNode name="slaves">
<properties>
<help>Show specified bonding interface information</help>
Expand Down
103 changes: 103 additions & 0 deletions src/op_mode/bonding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env python3
#
# Copyright (C) 2016-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This script will parse 'sudo cat /proc/net/bonding/<interface name>' and return table output for lacp related info

import subprocess
import re
import sys
import typing
from tabulate import tabulate

import vyos.opmode
from vyos.configquery import ConfigTreeQuery

def list_to_dict(data, headers, basekey):
data_list = {basekey: []}

for row in data:
row_dict = {headers[i]: row[i] for i in range(len(headers))}
data_list[basekey].append(row_dict)

return data_list

def show_lacp_neighbors(raw: bool, interface: typing.Optional[str]):
headers = ["Interface", "Member", "Local ID", "Remote ID"]
data = subprocess.run(f"cat /proc/net/bonding/{interface}", stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, shell=True, text=False).stdout.decode('utf-8')
if 'Bonding Mode: IEEE 802.3ad Dynamic link aggregation' not in data:
raise vyos.opmode.DataUnavailable(f"{interface} is not present or not configured with mode 802.3ad")

pattern = re.compile(
r"Slave Interface: (?P<member>\w+\d+).*?"
r"system mac address: (?P<local_id>[0-9a-f:]+).*?"
r"details partner lacp pdu:.*?"
r"system mac address: (?P<remote_id>[0-9a-f:]+)",
re.DOTALL
)

interfaces = []

for match in re.finditer(pattern, data):
member = match.group("member")
local_id = match.group("local_id")
remote_id = match.group("remote_id")
interfaces.append([interface, member, local_id, remote_id])

if raw:
return list_to_dict(interfaces, headers, 'lacp')
else:
return tabulate(interfaces, headers)

def show_lacp_detail(raw: bool, interface: typing.Optional[str]):
headers = ["Interface", "Members", "Mode", "Rate", "System-MAC", "Hash"]
query = ConfigTreeQuery()

if interface:
intList = [interface]
else:
intList = query.list_nodes(['interfaces', 'bonding'])

bondList = []

for interface in intList:
data = subprocess.run(f"cat /proc/net/bonding/{interface}", stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, shell=True, text=False).stdout.decode('utf-8')
if 'Bonding Mode: IEEE 802.3ad Dynamic link aggregation' not in data:
continue

mode_active = "active" if "LACP active: on" in data else "passive"
lacp_rate = re.search(r"LACP rate: (\w+)", data).group(1) if re.search(r"LACP rate: (\w+)", data) else "N/A"
hash_policy = re.search(r"Transmit Hash Policy: (.+?) \(\d+\)", data).group(1) if re.search(r"Transmit Hash Policy: (.+?) \(\d+\)", data) else "N/A"
system_mac = re.search(r"System MAC address: ([0-9a-f:]+)", data).group(1) if re.search(r"System MAC address: ([0-9a-f:]+)", data) else "N/A"
if raw:
members = re.findall(r"Slave Interface: ([a-zA-Z0-9:_-]+)", data)
else:
members = ",".join(set(re.findall(r"Slave Interface: ([a-zA-Z0-9:_-]+)", data)))

bondList.append([interface, members, mode_active, lacp_rate, system_mac, hash_policy])

if raw:
return list_to_dict(bondList, headers, 'lacp')
else:
return tabulate(bondList, headers)

if __name__ == '__main__':
try:
res = vyos.opmode.run(sys.modules[__name__])
if res:
print(res)
except (ValueError, vyos.opmode.Error) as e:
print(e)
sys.exit(1)
Loading