Merge "os-net-config runs ethtool command without restarting interfaces" into stable/zed

This commit is contained in:
Zuul 2023-03-15 11:47:04 +00:00 committed by Gerrit Code Review
commit e2d2f6c585
3 changed files with 164 additions and 1 deletions

View File

@ -260,7 +260,8 @@ class IfcfgNetConfig(os_net_config.NetConfig):
"IPADDR",
"NETMASK",
"MTU",
"ONBOOT"
"ONBOOT",
"ETHTOOL_OPTS"
]
# Check whether any of the changes require restart
for change in self.enumerate_ifcfg_changes(file_values, new_values):
@ -330,6 +331,46 @@ class IfcfgNetConfig(os_net_config.NetConfig):
commands.append("link set dev %s mtu 1500" % device_name)
return commands
def ethtool_apply_command(self, device_name, filename, data):
"""Return list of commands needed to implement changes.
Given ifcfg data for an interface, return commands required to
apply the configuration using 'ethtool' commands.
:param device_name: The name of the int, bridge, or bond
:type device_name: string
:param filename: The ifcfg-<int> filename.
:type filename: string
:param data: The data for the new ifcfg-<int> file.
:type data: string
:returns: commands (commands to be run)
"""
previous_cfg = common.get_file_data(filename)
file_values = self.parse_ifcfg(previous_cfg)
data_values = self.parse_ifcfg(data)
logger.debug("File values:\n%s" % file_values)
logger.debug("Data values:\n%s" % data_values)
changes = self.enumerate_ifcfg_changes(file_values, data_values)
commands = []
if "ETHTOOL_OPTS" in changes:
if changes["ETHTOOL_OPTS"] == "added" or \
changes["ETHTOOL_OPTS"] == "modified":
for command_opts in data_values["ETHTOOL_OPTS"].split(';'):
if re.match(r'\s*-+\w+-*\w* ', command_opts):
if device_name or "${DEVICE}" or "$DEVICE" \
in command_opts:
commands.append("%s" % command_opts)
else:
msg = ("Assigned interface name to \
ETHTOOL_OPTS is invalid %s" % device_name)
raise utils.InvalidInterfaceException(msg)
else:
commands.append("-s %s %s" %
(device_name, command_opts))
return commands
def iproute2_route_commands(self, filename, data):
"""Return a list of commands for 'ip route' to modify routing table.
@ -1310,6 +1351,7 @@ class IfcfgNetConfig(os_net_config.NetConfig):
vpp_interfaces = self.vpp_interface_data.values()
vpp_bonds = self.vpp_bond_data.values()
ipcmd = utils.iproute2_path()
ethtoolcmd = utils.ethtool_path()
for interface_name, iface_data in self.interface_data.items():
route_data = self.route_data.get(interface_name, '')
@ -1754,6 +1796,27 @@ class IfcfgNetConfig(os_net_config.NetConfig):
self.child_members(interface[0]))
break
commands = self.ethtool_apply_command(interface[0],
interface[1],
interface[2])
if commands is not None:
for command in commands:
try:
args = command.split()
args = [interface[0]
if item in ["${DEVICE}", "$DEVICE"]
else item for item in args]
self.execute('Running ethtool %s' % command,
ethtoolcmd, *args)
except Exception as e:
logger.warning("Error in 'ethtool %s', restarting %s:\
\n%s)" %
(command, interface[0], str(e)))
restart_interfaces.append(interface[0])
restart_interfaces.extend(
self.child_members(interface[0]))
break
for bridge in apply_bridges:
logger.debug('Running ip commands on bridge: %s' %
bridge[0])

View File

@ -104,6 +104,7 @@ BOOTPROTO="dhcp"
ONBOOT="yes"
TYPE="Ethernet"
"""
_IFCFG_STATIC1 = """# This file is autogenerated by os-net-config
DEVICE=eth0
BOOTPROTO=static
@ -115,6 +116,31 @@ ONBOOT=yes
_IFCFG_STATIC1_MTU = _IFCFG_STATIC1 + "\nMTU=9000"
_IFCFG_STATIC1_ETHTOOL1 = _IFCFG_STATIC1 +\
"\nETHTOOL_OPTS=\"speed 100 duplex full autoneg off\""
_IFCFG_STATIC1_ETHTOOL2 = _IFCFG_STATIC1 +\
"\nETHTOOL_OPTS=\"-G ${DEVICE} rx 1024 tx 1024\""
_IFCFG_STATIC1_ETHTOOL3 = _IFCFG_STATIC1 +\
"\nETHTOOL_OPTS=\"--set-ring ${DEVICE} rx 1024 tx 1024\""
_IFCFG_STATIC1_ETHTOOL4 = _IFCFG_STATIC1 +\
"\nETHTOOL_OPTS=\"--pause ${DEVICE} autoneg on\""
_IFCFG_STATIC1_ETHTOOL5 = _IFCFG_STATIC1 +\
"\nETHTOOL_OPTS=\"-G ${DEVICE} rx 1024 tx 1024;\
-A ${DEVICE} autoneg on;\
--pause ${DEVICE} autoneg off;\
--set-ring ${DEVICE} rx 512\""
_IFCFG_STATIC1_ETHTOOL6 = _IFCFG_STATIC1 +\
"\nETHTOOL_OPTS=\"-G $DEVICE rx 1024 tx 1024\""
_IFCFG_STATIC1_ETHTOOL7 = _IFCFG_STATIC1 +\
"\nETHTOOL_OPTS=\"-G eth0 rx 1024 tx 1024\""
_IFCFG_STATIC2 = """DEVICE=eth0
BOOTPROTO=static
IPADDR=10.0.1.2
@ -2539,6 +2565,8 @@ class TestIfcfgNetConfigApply(base.TestCase):
_IFCFG_ROUTES2)
self.assertTrue(commands == command_list1)
shutil.rmtree(tmpdir)
def test_ifcfg_rule_commands(self):
tmpdir = tempfile.mkdtemp()
@ -2557,6 +2585,8 @@ class TestIfcfgNetConfigApply(base.TestCase):
_IFCFG_RULES2)
self.assertTrue(commands == command_list1)
shutil.rmtree(tmpdir)
def test_ifcfg_ipmtu_commands(self):
tmpdir = tempfile.mkdtemp()
@ -2590,6 +2620,64 @@ class TestIfcfgNetConfigApply(base.TestCase):
_IFCFG_STATIC2_MTU)
self.assertTrue(commands == command_list3)
shutil.rmtree(tmpdir)
def test_ifcfg_ethtool_commands(self):
tmpdir = tempfile.mkdtemp()
interface = "eth0"
interface_filename = tmpdir + '/ifcfg-' + interface
file = open(interface_filename, 'w')
file.write(_IFCFG_STATIC1)
file.close()
command_list1 = ['-s eth0 speed 100 duplex full autoneg off']
command = self.provider.ethtool_apply_command(interface,
interface_filename,
_IFCFG_STATIC1_ETHTOOL1)
self.assertTrue(command == command_list1)
command_list2 = ['-G ${DEVICE} rx 1024 tx 1024']
command = self.provider.ethtool_apply_command(interface,
interface_filename,
_IFCFG_STATIC1_ETHTOOL2)
self.assertTrue(command == command_list2)
command_list3 = ['--set-ring ${DEVICE} rx 1024 tx 1024']
command = self.provider.ethtool_apply_command(interface,
interface_filename,
_IFCFG_STATIC1_ETHTOOL3)
self.assertTrue(command == command_list3)
command_list4 = ['--pause ${DEVICE} autoneg on']
command = self.provider.ethtool_apply_command(interface,
interface_filename,
_IFCFG_STATIC1_ETHTOOL4)
self.assertTrue(command == command_list4)
command_list5 = ['-G ${DEVICE} rx 1024 tx 1024',
'-A ${DEVICE} autoneg on',
'--pause ${DEVICE} autoneg off',
'--set-ring ${DEVICE} rx 512']
command = self.provider.ethtool_apply_command(interface,
interface_filename,
_IFCFG_STATIC1_ETHTOOL5)
self.assertTrue(command == command_list5)
command_list6 = ['-G $DEVICE rx 1024 tx 1024']
command = self.provider.ethtool_apply_command(interface,
interface_filename,
_IFCFG_STATIC1_ETHTOOL6)
self.assertTrue(command == command_list6)
command_list7 = ['-G eth0 rx 1024 tx 1024']
command = self.provider.ethtool_apply_command(interface,
interface_filename,
_IFCFG_STATIC1_ETHTOOL7)
self.assertTrue(command == command_list7)
shutil.rmtree(tmpdir)
def test_restart_children_on_change(self):
# setup and apply a bridge
interface = objects.Interface('em1')

View File

@ -851,3 +851,15 @@ def iproute2_path():
logger.warning("Could not execute /sbin/ip or /usr/sbin/ip")
return False
return ipcmd
def ethtool_path():
"""Find 'ethtool' executable."""
if os.access('/sbin/ethtool', os.X_OK):
ethtoolcmd = '/sbin/ethtool'
elif os.access('/usr/sbin/ethtool', os.X_OK):
ethtoolcmd = '/usr/sbin/ethtool'
else:
logger.warning("Could not execute /sbin/ethtool or /usr/sbin/ethtool")
return False
return ethtoolcmd