2019-08-04 21:48:06 +02:00
|
|
|
import re
|
2019-08-04 23:42:08 +02:00
|
|
|
import subprocess
|
2020-02-02 20:08:56 +01:00
|
|
|
from shutil import which
|
2019-08-04 21:48:06 +02:00
|
|
|
|
2019-08-04 14:37:51 +02:00
|
|
|
# Originally from https://github.com/opencoff/useful-scripts/blob/master/linktest.py
|
|
|
|
|
|
|
|
# mapping fields from ethtool output to simple names
|
2019-08-04 15:14:36 +02:00
|
|
|
field_map = {
|
2024-10-21 12:55:54 +02:00
|
|
|
"Supported ports": "ports",
|
|
|
|
"Supported link modes": "sup_link_modes",
|
|
|
|
"Supports auto-negotiation": "sup_autoneg",
|
|
|
|
"Advertised link modes": "adv_link_modes",
|
|
|
|
"Advertised auto-negotiation": "adv_autoneg",
|
|
|
|
"Speed": "speed",
|
|
|
|
"Duplex": "duplex",
|
|
|
|
"Port": "port",
|
|
|
|
"Auto-negotiation": "autoneg",
|
|
|
|
"Link detected": "link",
|
2019-08-04 14:37:51 +02:00
|
|
|
}
|
|
|
|
|
2019-08-04 15:14:36 +02:00
|
|
|
|
2019-08-06 18:15:08 +02:00
|
|
|
def merge_two_dicts(x, y):
|
|
|
|
z = x.copy()
|
|
|
|
z.update(y)
|
|
|
|
return z
|
|
|
|
|
|
|
|
|
2024-10-21 12:55:54 +02:00
|
|
|
class Ethtool:
|
2019-08-04 15:14:36 +02:00
|
|
|
"""
|
2019-08-04 21:48:06 +02:00
|
|
|
This class aims to parse ethtool output
|
|
|
|
There is several bindings to have something proper, but it requires
|
|
|
|
compilation and other requirements.
|
2019-08-04 15:14:36 +02:00
|
|
|
"""
|
2020-02-02 20:08:56 +01:00
|
|
|
|
2019-08-04 21:48:06 +02:00
|
|
|
def __init__(self, interface, *args, **kwargs):
|
|
|
|
self.interface = interface
|
|
|
|
|
|
|
|
def _parse_ethtool_output(self):
|
|
|
|
"""
|
|
|
|
parse ethtool output
|
|
|
|
"""
|
|
|
|
|
2024-10-21 12:55:54 +02:00
|
|
|
output = subprocess.getoutput("ethtool {}".format(self.interface))
|
2019-08-04 21:48:06 +02:00
|
|
|
|
|
|
|
fields = {}
|
2024-10-21 12:55:54 +02:00
|
|
|
field = ""
|
|
|
|
fields["speed"] = "-"
|
|
|
|
fields["link"] = "-"
|
|
|
|
fields["duplex"] = "-"
|
|
|
|
for line in output.split("\n")[1:]:
|
2019-08-04 21:48:06 +02:00
|
|
|
line = line.rstrip()
|
2024-10-21 12:55:54 +02:00
|
|
|
r = line.find(":")
|
2019-08-04 21:48:06 +02:00
|
|
|
if r > 0:
|
|
|
|
field = line[:r].strip()
|
|
|
|
if field not in field_map:
|
|
|
|
continue
|
|
|
|
field = field_map[field]
|
2024-10-21 12:55:54 +02:00
|
|
|
output = line[r + 1 :].strip()
|
2019-08-04 21:48:06 +02:00
|
|
|
fields[field] = output
|
|
|
|
else:
|
2024-10-21 12:55:54 +02:00
|
|
|
if len(field) > 0 and field in field_map:
|
|
|
|
fields[field] += " " + line.strip()
|
2019-08-04 21:48:06 +02:00
|
|
|
return fields
|
|
|
|
|
|
|
|
def _parse_ethtool_module_output(self):
|
2024-10-21 12:55:54 +02:00
|
|
|
status, output = subprocess.getstatusoutput(
|
|
|
|
"ethtool -m {}".format(self.interface)
|
|
|
|
)
|
2020-04-19 12:19:28 +02:00
|
|
|
if status == 0:
|
2024-10-21 12:55:54 +02:00
|
|
|
r = re.search(r"Identifier.*\((\w+)\)", output)
|
2020-04-19 12:19:28 +02:00
|
|
|
if r and len(r.groups()) > 0:
|
2024-10-21 12:55:54 +02:00
|
|
|
return {"form_factor": r.groups()[0]}
|
2020-04-19 12:19:28 +02:00
|
|
|
return {}
|
2019-08-04 14:37:51 +02:00
|
|
|
|
2019-08-04 21:48:06 +02:00
|
|
|
def parse(self):
|
2024-10-21 12:55:54 +02:00
|
|
|
if which("ethtool") is None:
|
2019-08-04 23:24:51 +02:00
|
|
|
return None
|
2019-08-08 10:42:43 +02:00
|
|
|
output = self._parse_ethtool_output()
|
|
|
|
output.update(self._parse_ethtool_module_output())
|
|
|
|
return output
|