Merge "os-net-config runs ethtool command without restarting interfaces" into stable/zed
This commit is contained in:
commit
e2d2f6c585
|
@ -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])
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue