summaryrefslogtreecommitdiff
path: root/python/vyos/ethtool.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/vyos/ethtool.py')
-rw-r--r--python/vyos/ethtool.py82
1 files changed, 73 insertions, 9 deletions
diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py
index 7dcb68346..609d83b5e 100644
--- a/python/vyos/ethtool.py
+++ b/python/vyos/ethtool.py
@@ -13,7 +13,9 @@
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
+import os
import re
+
from vyos.util import popen
class Ethtool:
@@ -41,8 +43,22 @@ class Ethtool:
# }
_speed_duplex = { }
_ring_buffers = { }
+ _ring_buffers_max = { }
+ _driver_name = None
+ _auto_negotiation = None
+ _flow_control = None
+ _flow_control_enabled = None
def __init__(self, ifname):
+ # Get driver used for interface
+ sysfs_file = f'/sys/class/net/{ifname}/device/driver/module'
+ if os.path.exists(sysfs_file):
+ link = os.readlink(sysfs_file)
+ self._driver_name = os.path.basename(link)
+
+ if not self._driver_name:
+ raise ValueError(f'Could not determine driver for interface {ifname}!')
+
# Build a dictinary of supported link-speed and dupley settings.
out, err = popen(f'ethtool {ifname}')
reading = False
@@ -53,7 +69,6 @@ class Ethtool:
reading = True
if 'Supported pause frame use:' in line:
reading = False
- break
if reading:
for block in line.split():
if pattern.search(block):
@@ -63,6 +78,15 @@ class Ethtool:
self._speed_duplex.update({ speed : {}})
if duplex not in self._speed_duplex[speed]:
self._speed_duplex[speed].update({ duplex : ''})
+ if 'Auto-negotiation:' in line:
+ # Split the following string: Auto-negotiation: off
+ # we are only interested in off or on
+ tmp = line.split()[-1]
+ self._auto_negotiation = bool(tmp == 'on')
+
+ if self._auto_negotiation == None:
+ raise ValueError(f'Could not determine auto-negotiation settings '\
+ f'for interface {ifname}!')
# Now populate features dictionaty
out, err = popen(f'ethtool --show-features {ifname}')
@@ -78,7 +102,7 @@ class Ethtool:
'fixed' : fixed
}
- out, err = popen(f'ethtool -g {ifname}')
+ out, err = popen(f'ethtool --show-ring {ifname}')
# We are only interested in line 2-5 which contains the device maximum
# ringbuffers
for line in out.splitlines()[2:6]:
@@ -89,7 +113,26 @@ class Ethtool:
# output format from 0 -> n/a. As we are only interested in the
# tx/rx keys we do not care about RX Mini/Jumbo.
if value.isdigit():
- self._ring_buffers[key] = int(value)
+ self._ring_buffers_max[key] = value
+ # Now we wan't to get the current RX/TX ringbuffer values - used for
+ for line in out.splitlines()[7:11]:
+ if ':' in line:
+ key, value = [s.strip() for s in line.strip().split(":", 1)]
+ key = key.lower().replace(' ', '_')
+ # T3645: ethtool version used on Debian Bullseye changed the
+ # output format from 0 -> n/a. As we are only interested in the
+ # tx/rx keys we do not care about RX Mini/Jumbo.
+ if value.isdigit():
+ self._ring_buffers[key] = value
+
+ # Get current flow control settings, but this is not supported by
+ # all NICs (e.g. vmxnet3 does not support is)
+ out, err = popen(f'ethtool --show-pause {ifname}')
+ if len(out.splitlines()) > 1:
+ self._flow_control = True
+ # read current flow control setting, this returns:
+ # ['Autonegotiate:', 'on']
+ self._flow_control_enabled = out.splitlines()[1].split()[-1]
def _get_generic(self, feature):
"""
@@ -122,15 +165,19 @@ class Ethtool:
def get_tcp_segmentation_offload(self):
return self._get_generic('tcp-segmentation-offload')
- def get_rx_buffer(self):
- # Configuration of RX ring-buffers is not supported on every device,
+ def get_ring_buffer_max(self, rx_tx):
+ # Configuration of RX/TX ring-buffers is not supported on every device,
# thus when it's impossible return None
- return self._ring_buffers.get('rx', None)
+ if rx_tx not in ['rx', 'tx']:
+ ValueError('Ring-buffer type must be either "rx" or "tx"')
+ return self._ring_buffers_max.get(rx_tx, None)
- def get_tx_buffer(self):
- # Configuration of TX ring-buffers is not supported on every device,
+ def get_ring_buffer(self, rx_tx):
+ # Configuration of RX/TX ring-buffers is not supported on every device,
# thus when it's impossible return None
- return self._ring_buffers.get('tx', None)
+ if rx_tx not in ['rx', 'tx']:
+ ValueError('Ring-buffer type must be either "rx" or "tx"')
+ return str(self._ring_buffers.get(rx_tx, None))
def check_speed_duplex(self, speed, duplex):
""" Check if the passed speed and duplex combination is supported by
@@ -142,8 +189,25 @@ class Ethtool:
if duplex not in ['full', 'half']:
raise ValueError(f'Value "{duplex}" for duplex is invalid!')
+ if self._driver_name in ['vmxnet3', 'virtio_net', 'xen_netfront']:
+ return False
+
if speed in self._speed_duplex:
if duplex in self._speed_duplex[speed]:
return True
return False
+ def check_flow_control(self):
+ """ Check if the NIC supports flow-control """
+ if self._driver_name in ['vmxnet3', 'virtio_net', 'xen_netfront']:
+ return False
+ return self._flow_control
+
+ def get_flow_control(self):
+ if self._flow_control_enabled == None:
+ raise ValueError('Interface does not support changing '\
+ 'flow-control settings!')
+ return self._flow_control_enabled
+
+ def get_auto_negotiation(self):
+ return self._auto_negotiation