functions: use iw for Wi-Fi power saving
The powersave profiles still use the Wireless Extensions iwpriv tool, which Fedora no longer installs. As a result, enabling these profiles leaves Wi-Fi power saving unchanged. Prefer the nl80211-based iw command and translate the profile actions to explicit on and off states. Fall back to iwpriv per interface for legacy drivers, and retain the existing sysfs fallback. Require iw in the RPM spec and cover the modern and legacy paths with unit tests. Fixes #836 Resolves: rhbz#2372365 Signed-off-by: Junjie Cao <junjie.cao@intel.com>
This commit is contained in:
parent
0eb28ac3d8
commit
f5e0632b11
3 changed files with 170 additions and 6 deletions
30
functions
30
functions
|
|
@ -299,26 +299,44 @@ restore_transparent_hugepages() {
|
|||
# WIFI tuning
|
||||
#
|
||||
|
||||
# usage: _wifi_set_power_level level
|
||||
# usage: _wifi_set_power_level level [wireless_status_file]
|
||||
_wifi_set_power_level() {
|
||||
# 0 auto, PM enabled
|
||||
# 1-5 least savings and lowest latency - most savings and highest latency
|
||||
# 6 disable power savings
|
||||
level=$1
|
||||
wireless_status_file=${2:-/proc/net/wireless}
|
||||
|
||||
# do not report errors on systems with no wireless
|
||||
[ -e /proc/net/wireless ] || return 0
|
||||
[ -e "$wireless_status_file" ] || return 0
|
||||
|
||||
# apply the settings using iwpriv
|
||||
ifaces=$(cat /proc/net/wireless | grep -v '|' | sed 's@^ *\([^:]*\):.*@\1@')
|
||||
case "$level" in
|
||||
0|6)
|
||||
power_save=off
|
||||
;;
|
||||
*)
|
||||
power_save=on
|
||||
;;
|
||||
esac
|
||||
|
||||
ifaces=$(grep -v '|' "$wireless_status_file" | sed 's@^ *\([^:]*\):.*@\1@')
|
||||
for iface in $ifaces; do
|
||||
iwpriv $iface set_power $level
|
||||
if command -v iw >/dev/null 2>&1; then
|
||||
iw dev "$iface" set power_save "$power_save" && continue
|
||||
fi
|
||||
|
||||
# Keep support for legacy drivers using Wireless Extensions.
|
||||
if command -v iwpriv >/dev/null 2>&1; then
|
||||
iwpriv "$iface" set_power "$level"
|
||||
fi
|
||||
done
|
||||
|
||||
# some adapters may rely on sysfs
|
||||
for i in /sys/bus/pci/devices/*/power_level; do
|
||||
(echo $level > $i) &> /dev/null
|
||||
(echo "$level" > "$i") &> /dev/null
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
enable_wifi_powersave() {
|
||||
|
|
|
|||
145
tests/unit/test_functions.py
Normal file
145
tests/unit/test_functions.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
|
||||
class WifiPowerSaveTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self._repo_dir = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), "..", "..")
|
||||
)
|
||||
self._test_dir = tempfile.mkdtemp()
|
||||
self._bin_dir = os.path.join(self._test_dir, "bin")
|
||||
os.mkdir(self._bin_dir)
|
||||
self._log = os.path.join(self._test_dir, "commands.log")
|
||||
self._wireless = os.path.join(self._test_dir, "wireless")
|
||||
self._write_file(
|
||||
self._wireless,
|
||||
"""\
|
||||
Inter-| sta-| Quality | Discarded packets | Missed | WE
|
||||
face | tus | link level noise | nwid crypt frag retry misc | beacon | 22
|
||||
wlan0: 0000 0. 0. 0. 0 0 0 0 0 0
|
||||
wlan1: 0000 0. 0. 0. 0 0 0 0 0 0
|
||||
"""
|
||||
)
|
||||
for command in ("grep", "ls", "sed"):
|
||||
os.symlink("/bin/" + command, os.path.join(self._bin_dir, command))
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self._test_dir)
|
||||
|
||||
def _write_file(self, path, content):
|
||||
with open(path, "w") as output:
|
||||
output.write(content)
|
||||
|
||||
def _write_command(self, name, body):
|
||||
command = os.path.join(self._bin_dir, name)
|
||||
self._write_file(command, "#!/bin/bash\n" + body.lstrip())
|
||||
os.chmod(command, 0o755)
|
||||
|
||||
def _run(self, level):
|
||||
env = os.environ.copy()
|
||||
env["COMMAND_LOG"] = self._log
|
||||
env["PATH"] = self._bin_dir
|
||||
subprocess.check_call(
|
||||
[
|
||||
"/bin/bash",
|
||||
"-c",
|
||||
'. "$1"; _wifi_set_power_level "$2" "$3"',
|
||||
"bash",
|
||||
os.path.join(self._repo_dir, "functions"),
|
||||
str(level),
|
||||
self._wireless,
|
||||
],
|
||||
env=env,
|
||||
)
|
||||
if os.path.exists(self._log):
|
||||
with open(self._log) as command_log:
|
||||
return command_log.read().splitlines()
|
||||
return []
|
||||
|
||||
def test_iw_enables_power_save_on_all_interfaces(self):
|
||||
self._write_command("iw", 'echo "iw $*" >> "$COMMAND_LOG"\n')
|
||||
self._write_command("iwpriv", 'echo "iwpriv $*" >> "$COMMAND_LOG"\n')
|
||||
|
||||
self.assertEqual(
|
||||
self._run(5),
|
||||
[
|
||||
"iw dev wlan0 set power_save on",
|
||||
"iw dev wlan1 set power_save on",
|
||||
],
|
||||
)
|
||||
|
||||
def test_iw_disables_power_save_on_all_interfaces(self):
|
||||
self._write_command("iw", 'echo "iw $*" >> "$COMMAND_LOG"\n')
|
||||
|
||||
self.assertEqual(
|
||||
self._run(0),
|
||||
[
|
||||
"iw dev wlan0 set power_save off",
|
||||
"iw dev wlan1 set power_save off",
|
||||
],
|
||||
)
|
||||
|
||||
def test_iw_maps_legacy_disable_level_to_off(self):
|
||||
self._write_command("iw", 'echo "iw $*" >> "$COMMAND_LOG"\n')
|
||||
|
||||
self.assertEqual(
|
||||
self._run(6),
|
||||
[
|
||||
"iw dev wlan0 set power_save off",
|
||||
"iw dev wlan1 set power_save off",
|
||||
],
|
||||
)
|
||||
|
||||
def test_iwpriv_fallback_when_iw_is_unavailable(self):
|
||||
self._write_command("iwpriv", 'echo "iwpriv $*" >> "$COMMAND_LOG"\n')
|
||||
|
||||
self.assertEqual(
|
||||
self._run(5),
|
||||
[
|
||||
"iwpriv wlan0 set_power 5",
|
||||
"iwpriv wlan1 set_power 5",
|
||||
],
|
||||
)
|
||||
|
||||
def test_iwpriv_fallback_when_iw_rejects_interface(self):
|
||||
self._write_command(
|
||||
"iw",
|
||||
"""
|
||||
echo "iw $*" >> "$COMMAND_LOG"
|
||||
exit 1
|
||||
""",
|
||||
)
|
||||
self._write_command("iwpriv", 'echo "iwpriv $*" >> "$COMMAND_LOG"\n')
|
||||
|
||||
self.assertEqual(
|
||||
self._run(5),
|
||||
[
|
||||
"iw dev wlan0 set power_save on",
|
||||
"iwpriv wlan0 set_power 5",
|
||||
"iw dev wlan1 set power_save on",
|
||||
"iwpriv wlan1 set_power 5",
|
||||
],
|
||||
)
|
||||
|
||||
def test_missing_tools_are_ignored(self):
|
||||
self.assertEqual(self._run(5), [])
|
||||
|
||||
def test_no_interfaces_are_ignored(self):
|
||||
self._write_file(
|
||||
self._wireless,
|
||||
"""\
|
||||
Inter-| sta-| Quality | Discarded packets | Missed | WE
|
||||
face | tus | link level noise | nwid crypt frag retry misc | beacon | 22
|
||||
"""
|
||||
)
|
||||
self._write_command("iw", 'echo "iw $*" >> "$COMMAND_LOG"\n')
|
||||
|
||||
self.assertEqual(self._run(5), [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
@ -106,6 +106,7 @@ Requires: pygobject3-base
|
|||
%endif
|
||||
Requires: virt-what
|
||||
Requires: ethtool
|
||||
Requires: iw
|
||||
Requires: gawk
|
||||
Requires: util-linux
|
||||
Requires: dbus
|
||||
|
|
|
|||
Loading…
Reference in a new issue