Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F118307143
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/op-mode-definitions/show-interfaces-ethernet.xml.in b/op-mode-definitions/show-interfaces-ethernet.xml.in
index fc79f44bf..6d50d6e90 100644
--- a/op-mode-definitions/show-interfaces-ethernet.xml.in
+++ b/op-mode-definitions/show-interfaces-ethernet.xml.in
@@ -1,97 +1,97 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="show">
<children>
<node name="interfaces">
<children>
<tagNode name="ethernet">
<properties>
<help>Show ethernet interface information</help>
<completionHelp>
<path>interfaces ethernet</path>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/show_interfaces.py --intf="$4"</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of the specified ethernet interface information</help>
</properties>
<command>${vyos_op_scripts_dir}/show_interfaces.py --intf="$4" --action=show-brief</command>
</leafNode>
<leafNode name="identify">
<properties>
<help>Visually identify specified ethernet interface</help>
</properties>
- <command>echo "Blinking interface $4 for 30 seconds."; /sbin/ethtool --identify "$4" 30</command>
+ <command>echo "Blinking interface $4 for 30 seconds."; ethtool --identify "$4" 30</command>
</leafNode>
<node name="physical">
<properties>
<help>Show physical device information for specified ethernet interface</help>
</properties>
- <command>/sbin/ethtool "$4"; /sbin/ethtool -i "$4"</command>
+ <command>ethtool "$4"; ethtool --driver "$4"</command>
<children>
<leafNode name="offload">
<properties>
<help>Show physical device offloading capabilities</help>
</properties>
- <command>/sbin/ethtool -k "$4" | sed -e 1d -e '/fixed/d' -e 's/^\t*//g' -e 's/://' | column -t -s' '</command>
+ <command>ethtool --show-features "$4" | sed -e 1d -e '/fixed/d' -e 's/^\t*//g' -e 's/://' | column -t -s' '</command>
</leafNode>
</children>
</node>
<leafNode name="statistics">
<properties>
<help>Show physical device statistics for specified ethernet interface</help>
</properties>
- <command>/sbin/ethtool -S "$4"</command>
+ <command>ethtool --statistics "$4"</command>
</leafNode>
<leafNode name="transceiver">
<properties>
<help>Show transceiver information from modules (e.g SFP+, QSFP)</help>
</properties>
- <command>/sbin/ethtool -m "$4"</command>
+ <command>ethtool --module-info "$4"</command>
</leafNode>
<tagNode name="vif">
<properties>
<help>Show specified virtual network interface (vif) information</help>
<completionHelp>
<path>interfaces ethernet ${COMP_WORDS[3]} vif</path>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/show_interfaces.py --intf="$4.$6"</command>
<children>
<leafNode name="brief">
<properties>
<help>Show summary of specified virtual network interface (vif) information</help>
</properties>
<command>${vyos_op_scripts_dir}/show_interfaces.py --intf="$4.$6" --action=show-brief</command>
</leafNode>
</children>
</tagNode>
<leafNode name="xdp">
<properties>
<help>Show eXpress Data Path statistics</help>
</properties>
<command>sudo ${vyos_op_scripts_dir}/show_xdp_stats.sh ethernet "$4"</command>
</leafNode>
</children>
</tagNode>
<node name="ethernet">
<properties>
<help>Show ethernet interface information</help>
</properties>
<command>${vyos_op_scripts_dir}/show_interfaces.py --intf-type=ethernet --action=show-brief</command>
<children>
<leafNode name="detail">
<properties>
<help>Show detailed ethernet interface information</help>
</properties>
<command>${vyos_op_scripts_dir}/show_interfaces.py --intf-type=ethernet --action=show</command>
</leafNode>
</children>
</node>
</children>
</node>
</children>
</node>
</interfaceDefinition>
diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py
index 5a5d84bed..7dcb68346 100644
--- a/python/vyos/ethtool.py
+++ b/python/vyos/ethtool.py
@@ -1,149 +1,149 @@
# Copyright 2021 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# 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 re
from vyos.util import popen
class Ethtool:
"""
Class is used to retrive and cache information about an ethernet adapter
"""
# dictionary containing driver featurs, it will be populated on demand and
# the content will look like:
# {
# 'tls-hw-tx-offload': {'fixed': True, 'enabled': False},
# 'tx-checksum-fcoe-crc': {'fixed': True, 'enabled': False},
# 'tx-checksum-ip-generic': {'fixed': False, 'enabled': True},
# 'tx-checksum-ipv4': {'fixed': True, 'enabled': False},
# 'tx-checksum-ipv6': {'fixed': True, 'enabled': False},
# 'tx-checksum-sctp': {'fixed': True, 'enabled': False},
# 'tx-checksumming': {'fixed': False, 'enabled': True},
# 'tx-esp-segmentation': {'fixed': True, 'enabled': False},
# }
_features = { }
# dictionary containing available interface speed and duplex settings
# {
# '10' : {'full': '', 'half': ''},
# '100' : {'full': '', 'half': ''},
# '1000': {'full': ''}
# }
_speed_duplex = { }
_ring_buffers = { }
def __init__(self, ifname):
# Build a dictinary of supported link-speed and dupley settings.
out, err = popen(f'ethtool {ifname}')
reading = False
pattern = re.compile(r'\d+base.*')
for line in out.splitlines()[1:]:
line = line.lstrip()
if 'Supported link modes:' in line:
reading = True
if 'Supported pause frame use:' in line:
reading = False
break
if reading:
for block in line.split():
if pattern.search(block):
speed = block.split('base')[0]
duplex = block.split('/')[-1].lower()
if speed not in self._speed_duplex:
self._speed_duplex.update({ speed : {}})
if duplex not in self._speed_duplex[speed]:
self._speed_duplex[speed].update({ duplex : ''})
# Now populate features dictionaty
- out, err = popen(f'ethtool -k {ifname}')
+ out, err = popen(f'ethtool --show-features {ifname}')
# skip the first line, it only says: "Features for eth0":
for line in out.splitlines()[1:]:
if ":" in line:
key, value = [s.strip() for s in line.strip().split(":", 1)]
fixed = bool('fixed' in value)
if fixed:
value = value.split()[0].strip()
self._features[key.strip()] = {
'enabled' : bool(value == 'on'),
'fixed' : fixed
}
out, err = popen(f'ethtool -g {ifname}')
# We are only interested in line 2-5 which contains the device maximum
# ringbuffers
for line in out.splitlines()[2:6]:
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] = int(value)
def _get_generic(self, feature):
"""
Generic method to read self._features and return a tuple for feature
enabled and feature is fixed.
In case of a missing key, return "fixed = True and enabled = False"
"""
fixed = True
enabled = False
if feature in self._features:
if 'enabled' in self._features[feature]:
enabled = self._features[feature]['enabled']
if 'fixed' in self._features[feature]:
fixed = self._features[feature]['fixed']
return enabled, fixed
def get_generic_receive_offload(self):
return self._get_generic('generic-receive-offload')
def get_generic_segmentation_offload(self):
return self._get_generic('generic-segmentation-offload')
def get_large_receive_offload(self):
return self._get_generic('large-receive-offload')
def get_scatter_gather(self):
return self._get_generic('scatter-gather')
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,
# thus when it's impossible return None
return self._ring_buffers.get('rx', None)
def get_tx_buffer(self):
# Configuration of TX ring-buffers is not supported on every device,
# thus when it's impossible return None
return self._ring_buffers.get('tx', None)
def check_speed_duplex(self, speed, duplex):
""" Check if the passed speed and duplex combination is supported by
the underlaying network adapter. """
if isinstance(speed, int):
speed = str(speed)
if not speed.isdigit():
raise ValueError(f'Value "{speed}" for speed is invalid!')
if duplex not in ['full', 'half']:
raise ValueError(f'Value "{duplex}" for duplex is invalid!')
if speed in self._speed_duplex:
if duplex in self._speed_duplex[speed]:
return True
return False
diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py
index 7d29da8fc..76ed3fd92 100644
--- a/python/vyos/ifconfig/ethernet.py
+++ b/python/vyos/ifconfig/ethernet.py
@@ -1,393 +1,388 @@
# Copyright 2019-2021 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# 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.ethtool import Ethtool
from vyos.ifconfig.interface import Interface
from vyos.util import run
from vyos.util import dict_search
from vyos.validate import assert_list
@Interface.register
class EthernetIf(Interface):
"""
Abstraction of a Linux Ethernet Interface
"""
iftype = 'ethernet'
definition = {
**Interface.definition,
**{
'section': 'ethernet',
'prefixes': ['lan', 'eth', 'eno', 'ens', 'enp', 'enx'],
'bondable': True,
'broadcast': True,
'bridgeable': True,
'eternal': '(lan|eth|eno|ens|enp|enx)[0-9]+$',
}
}
@staticmethod
def feature(ifname, option, value):
- run(f'ethtool -K {ifname} {option} {value}')
+ run(f'ethtool --features {ifname} {option} {value}')
return False
_command_set = {**Interface._command_set, **{
'gro': {
'validate': lambda v: assert_list(v, ['on', 'off']),
'possible': lambda i, v: EthernetIf.feature(i, 'gro', v),
- # 'shellcmd': 'ethtool -K {ifname} gro {value}',
},
'gso': {
'validate': lambda v: assert_list(v, ['on', 'off']),
'possible': lambda i, v: EthernetIf.feature(i, 'gso', v),
- # 'shellcmd': 'ethtool -K {ifname} gso {value}',
},
'lro': {
'validate': lambda v: assert_list(v, ['on', 'off']),
'possible': lambda i, v: EthernetIf.feature(i, 'lro', v),
- # 'shellcmd': 'ethtool -K {ifname} lro {value}',
},
'sg': {
'validate': lambda v: assert_list(v, ['on', 'off']),
'possible': lambda i, v: EthernetIf.feature(i, 'sg', v),
- # 'shellcmd': 'ethtool -K {ifname} sg {value}',
},
'tso': {
'validate': lambda v: assert_list(v, ['on', 'off']),
'possible': lambda i, v: EthernetIf.feature(i, 'tso', v),
- # 'shellcmd': 'ethtool -K {ifname} tso {value}',
},
}}
_sysfs_set = {**Interface._sysfs_set, **{
'rps': {
'convert': lambda cpus: cpus if cpus else '0',
'location': '/sys/class/net/{ifname}/queues/rx-0/rps_cpus',
},
}}
def __init__(self, ifname, **kargs):
super().__init__(ifname, **kargs)
self.ethtool = Ethtool(ifname)
def get_driver_name(self):
"""
Return the driver name used by NIC. Some NICs don't support all
features e.g. changing link-speed, duplex
Example:
>>> from vyos.ifconfig import EthernetIf
>>> i = EthernetIf('eth0')
>>> i.get_driver_name()
'vmxnet3'
"""
ifname = self.config['ifname']
sysfs_file = f'/sys/class/net/{ifname}/device/driver/module'
if os.path.exists(sysfs_file):
link = os.readlink(sysfs_file)
return os.path.basename(link)
else:
return None
def set_flow_control(self, enable):
"""
Changes the pause parameters of the specified Ethernet device.
@param enable: true -> enable pause frames, false -> disable pause frames
Example:
>>> from vyos.ifconfig import EthernetIf
>>> i = EthernetIf('eth0')
>>> i.set_flow_control(True)
"""
ifname = self.config['ifname']
if enable not in ['on', 'off']:
raise ValueError("Value out of range")
driver_name = self.get_driver_name()
if driver_name in ['vmxnet3', 'virtio_net', 'xen_netfront']:
self._debug_msg(f'{driver_name} driver does not support changing '\
'flow control settings!')
return
# Get current flow control settings:
cmd = f'ethtool --show-pause {ifname}'
output, code = self._popen(cmd)
if code == 76:
# the interface does not support it
return ''
if code:
# never fail here as it prevent vyos to boot
print(f'unexpected return code {code} from {cmd}')
return ''
# The above command returns - with tabs:
#
# Pause parameters for eth0:
# Autonegotiate: on
# RX: off
# TX: off
if re.search("Autonegotiate:\ton", output):
if enable == "on":
# flowcontrol is already enabled - no need to re-enable it again
# this will prevent the interface from flapping as applying the
# flow-control settings will take the interface down and bring
# it back up every time.
return ''
# Assemble command executed on system. Unfortunately there is no way
# to change this setting via sysfs
cmd = f'ethtool --pause {ifname} autoneg {enable} tx {enable} rx {enable}'
output, code = self._popen(cmd)
if code:
print(f'could not set flowcontrol for {ifname}')
return output
def set_speed_duplex(self, speed, duplex):
"""
Set link speed in Mbit/s and duplex.
@speed can be any link speed in MBit/s, e.g. 10, 100, 1000 auto
@duplex can be half, full, auto
Example:
>>> from vyos.ifconfig import EthernetIf
>>> i = EthernetIf('eth0')
>>> i.set_speed_duplex('auto', 'auto')
"""
if speed not in ['auto', '10', '100', '1000', '2500', '5000', '10000',
'25000', '40000', '50000', '100000', '400000']:
raise ValueError("Value out of range (speed)")
if duplex not in ['auto', 'full', 'half']:
raise ValueError("Value out of range (duplex)")
driver_name = self.get_driver_name()
if driver_name in ['vmxnet3', 'virtio_net', 'xen_netfront']:
self._debug_msg(f'{driver_name} driver does not support changing '\
'speed/duplex settings!')
return
# Get current speed and duplex settings:
ifname = self.config['ifname']
cmd = f'ethtool {ifname}'
tmp = self._cmd(cmd)
if re.search("\tAuto-negotiation: on", tmp):
if speed == 'auto' and duplex == 'auto':
# bail out early as nothing is to change
return
else:
# read in current speed and duplex settings
cur_speed = 0
cur_duplex = ''
for line in tmp.splitlines():
if line.lstrip().startswith("Speed:"):
non_decimal = re.compile(r'[^\d.]+')
cur_speed = non_decimal.sub('', line)
continue
if line.lstrip().startswith("Duplex:"):
cur_duplex = line.split()[-1].lower()
break
if (cur_speed == speed) and (cur_duplex == duplex):
# bail out early as nothing is to change
return
cmd = f'ethtool -s {ifname}'
if speed == 'auto' or duplex == 'auto':
cmd += ' autoneg on'
else:
cmd += f' speed {speed} duplex {duplex} autoneg off'
return self._cmd(cmd)
def set_gro(self, state):
"""
Enable Generic Receive Offload. State can be either True or False.
Example:
>>> from vyos.ifconfig import EthernetIf
>>> i = EthernetIf('eth0')
>>> i.set_gro(True)
"""
if not isinstance(state, bool):
raise ValueError('Value out of range')
enabled, fixed = self.ethtool.get_generic_receive_offload()
if enabled != state:
if not fixed:
return self.set_interface('gro', 'on' if state else 'off')
else:
print('Adapter does not support changing generic-receive-offload settings!')
return False
def set_gso(self, state):
"""
Enable Generic Segmentation offload. State can be either True or False.
Example:
>>> from vyos.ifconfig import EthernetIf
>>> i = EthernetIf('eth0')
>>> i.set_gso(True)
"""
if not isinstance(state, bool):
raise ValueError('Value out of range')
enabled, fixed = self.ethtool.get_generic_segmentation_offload()
if enabled != state:
if not fixed:
return self.set_interface('gso', 'on' if state else 'off')
else:
print('Adapter does not support changing generic-segmentation-offload settings!')
return False
def set_lro(self, state):
"""
Enable Large Receive offload. State can be either True or False.
Example:
>>> from vyos.ifconfig import EthernetIf
>>> i = EthernetIf('eth0')
>>> i.set_lro(True)
"""
if not isinstance(state, bool):
raise ValueError('Value out of range')
enabled, fixed = self.ethtool.get_large_receive_offload()
if enabled != state:
if not fixed:
return self.set_interface('gro', 'on' if state else 'off')
else:
print('Adapter does not support changing large-receive-offload settings!')
return False
def set_rps(self, state):
if not isinstance(state, bool):
raise ValueError('Value out of range')
rps_cpus = '0'
if state:
# Enable RPS on all available CPUs except CPU0 which we will not
# utilize so the system has one spare core when it's under high
# preasure to server other means. Linux sysfs excepts a bitmask
# representation of the CPUs which should participate on RPS, we
# can enable more CPUs that are physically present on the system,
# Linux will clip that internally!
rps_cpus = 'ffffffff,ffffffff,ffffffff,fffffffe'
# send bitmask representation as hex string without leading '0x'
return self.set_interface('rps', rps_cpus)
def set_sg(self, state):
"""
Enable Scatter-Gather support. State can be either True or False.
Example:
>>> from vyos.ifconfig import EthernetIf
>>> i = EthernetIf('eth0')
>>> i.set_sg(True)
"""
if not isinstance(state, bool):
raise ValueError('Value out of range')
enabled, fixed = self.ethtool.get_scatter_gather()
if enabled != state:
if not fixed:
return self.set_interface('gro', 'on' if state else 'off')
else:
print('Adapter does not support changing scatter-gather settings!')
return False
def set_tso(self, state):
"""
Enable TCP segmentation offloading. State can be either True or False.
Example:
>>> from vyos.ifconfig import EthernetIf
>>> i = EthernetIf('eth0')
>>> i.set_tso(False)
"""
if not isinstance(state, bool):
raise ValueError('Value out of range')
enabled, fixed = self.ethtool.get_tcp_segmentation_offload()
if enabled != state:
if not fixed:
return self.set_interface('gro', 'on' if state else 'off')
else:
print('Adapter does not support changing tcp-segmentation-offload settings!')
return False
def set_ring_buffer(self, b_type, b_size):
"""
Example:
>>> from vyos.ifconfig import EthernetIf
>>> i = EthernetIf('eth0')
>>> i.set_ring_buffer('rx', '4096')
"""
ifname = self.config['ifname']
cmd = f'ethtool -G {ifname} {b_type} {b_size}'
output, code = self._popen(cmd)
# ethtool error codes:
# 80 - value already setted
# 81 - does not possible to set value
if code and code != 80:
print(f'could not set "{b_type}" ring-buffer for {ifname}')
return output
def update(self, config):
""" General helper function which works on a dictionary retrived by
get_config_dict(). It's main intention is to consolidate the scattered
interface setup code and provide a single point of entry when workin
on any interface. """
# disable ethernet flow control (pause frames)
value = 'off' if 'disable_flow_control' in config else 'on'
self.set_flow_control(value)
# GRO (generic receive offload)
self.set_gro(dict_search('offload.gro', config) != None)
# GSO (generic segmentation offload)
self.set_gso(dict_search('offload.gso', config) != None)
# LRO (large receive offload)
self.set_lro(dict_search('offload.lro', config) != None)
# RPS - Receive Packet Steering
self.set_rps(dict_search('offload.rps', config) != None)
# scatter-gather option
self.set_sg(dict_search('offload.sg', config) != None)
# TSO (TCP segmentation offloading)
self.set_tso(dict_search('offload.tso', config) != None)
# Set physical interface speed and duplex
if {'speed', 'duplex'} <= set(config):
speed = config.get('speed')
duplex = config.get('duplex')
self.set_speed_duplex(speed, duplex)
# Set interface ring buffer
if 'ring_buffer' in config:
for b_type in config['ring_buffer']:
self.set_ring_buffer(b_type, config['ring_buffer'][b_type])
# call base class first
super().update(config)
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Oct 17, 12:24 AM (7 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4403415
Default Alt Text
(25 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment