network: set routing preference only from settings

fixes #3068
This commit is contained in:
bbedward
2026-10-06 15:02:12 -04:00
parent d838d15e69
commit 089dc98166
6 changed files with 48 additions and 67 deletions
+14 -9
View File
@@ -16,7 +16,8 @@ const (
metricPreferred = int64(100)
metricNonPreferred = int64(300)
metricDefault = int64(100)
// -1 lets NetworkManager pick the metric by device type (nm-settings ipv4.route-metric)
metricDefault = int64(-1)
)
func (m *Manager) SetConnectionPreference(pref ConnectionPreference) error {
@@ -46,7 +47,7 @@ func (m *Manager) SetConnectionPreference(pref ConnectionPreference) error {
case PreferenceCellular:
return m.prioritizeCellular()
case PreferenceAuto:
return m.balancePriorities()
return m.restoreDefaultPriorities()
}
return nil
@@ -112,7 +113,7 @@ func (m *Manager) prioritizeCellular() error {
return nil
}
func (m *Manager) balancePriorities() error {
func (m *Manager) restoreDefaultPriorities() error {
if err := m.setConnectionPriority("802-3-ethernet", priorityDefault, metricDefault); err != nil {
log.Warnf("Failed to reset Ethernet priority: %v", err)
}
@@ -242,16 +243,20 @@ func (m *Manager) setConnectionPriority(connType string, autoconnectPriority int
}
func priorityMatches(variant dbus.Variant, expected int64) bool {
value, ok := variantInt64(variant)
return ok && value == expected
return settingInt64(variant, int64(priorityDefault)) == expected
}
func routeMetricMatches(section map[string]dbus.Variant, expected int64) bool {
if section == nil {
return false
return settingInt64(section["route-metric"], metricDefault) == expected
}
// GetSettings omits properties at their default, so a missing key is the default value
func settingInt64(variant dbus.Variant, def int64) int64 {
value, ok := variantInt64(variant)
if !ok {
return def
}
value, ok := variantInt64(section["route-metric"])
return ok && value == expected
return value
}
func variantInt64(variant dbus.Variant) (int64, bool) {
@@ -3,6 +3,7 @@ package network
import (
"testing"
"github.com/godbus/dbus/v5"
"github.com/stretchr/testify/assert"
)
@@ -20,7 +21,10 @@ func TestManager_SetConnectionPreference(t *testing.T) {
})
}
// Note: Full testing of priority operations would require mocking NetworkManager
// D-Bus interfaces. The tests above cover the basic logic and error handling.
// Integration tests would be needed for complete coverage of network connection
// priority updates and reactivation.
func TestProfileAtDefaultsMatchesAutoTargets(t *testing.T) {
assert.True(t, priorityMatches(dbus.Variant{}, int64(priorityDefault)))
assert.True(t, routeMetricMatches(nil, metricDefault))
assert.True(t, routeMetricMatches(map[string]dbus.Variant{"method": dbus.MakeVariant("auto")}, metricDefault))
assert.False(t, routeMetricMatches(map[string]dbus.Variant{"route-metric": dbus.MakeVariant(int64(100))}, metricDefault))
assert.False(t, priorityMatches(dbus.MakeVariant(int32(100)), int64(priorityDefault)))
}
@@ -52,7 +52,7 @@ Item {
readonly property string currentConnectionType: {
if (selectedType && connectionTypes.includes(selectedType))
return selectedType;
return connectionTypes[Math.max(0, currentPreferenceIndex)] || "wifi";
return connectionTypes[defaultTypeIndex] || "wifi";
}
readonly property bool wifiMode: currentConnectionType === "wifi"
readonly property bool ethernetMode: currentConnectionType === "ethernet"
@@ -66,18 +66,21 @@ Item {
readonly property bool wifiScanningEmpty: wifiMode && NetworkService.wifiEnabled && !NetworkService.wifiToggling && NetworkService.wifiInterface && (NetworkService.wifiNetworks?.length ?? 0) < 1 && (NetworkService.isScanning || transitioning)
readonly property bool wifiListVisible: wifiMode && NetworkService.wifiEnabled && !NetworkService.wifiToggling && !wifiScanningEmpty
readonly property int currentPreferenceIndex: {
if (DMSService.apiVersion < 5)
return 1;
if (!networkManager || DMSService.apiVersion <= 10)
return 1;
const pref = NetworkService.userPreference;
if (connectionTypes.indexOf(pref) !== -1)
return connectionTypes.indexOf(pref);
if (connectionTypes.indexOf(NetworkService.networkStatus) !== -1)
return connectionTypes.indexOf(NetworkService.networkStatus);
const wifiIndex = connectionTypes.indexOf("wifi");
return wifiIndex !== -1 ? wifiIndex : 0;
readonly property bool paneSwitchSupported: connectionTypes.length > 1 && networkManager && DMSService.apiVersion > 10
readonly property var typeLabels: ({
"ethernet": I18n.tr("Ethernet"),
"wifi": I18n.tr("Wi-Fi", "wireless network, page and section title"),
"cellular": I18n.tr("Cellular")
})
readonly property int defaultTypeIndex: {
const wifiIndex = Math.max(0, connectionTypes.indexOf("wifi"));
if (!paneSwitchSupported)
return wifiIndex;
const byStatus = connectionTypes.indexOf(NetworkService.networkStatus);
if (byStatus !== -1)
return byStatus;
const byPreference = connectionTypes.indexOf(NetworkService.userPreference);
return byPreference !== -1 ? byPreference : wifiIndex;
}
readonly property Item headerActions: Row {
@@ -318,23 +321,16 @@ Item {
bottomPadding: pageList.count > 0 ? CcMetrics.detailContentGap : 0
DButtonGroup {
readonly property var labelsByType: ({
"ethernet": I18n.tr("Ethernet"),
"wifi": I18n.tr("Wi-Fi", "wireless network, page and section title"),
"cellular": I18n.tr("Cellular")
})
anchors.horizontalCenter: parent.horizontalCenter
size: "small"
visible: root.connectionTypes.length > 1 && root.networkManager && DMSService.apiVersion > 10
model: root.connectionTypes.map(t => labelsByType[t] || t)
visible: root.paneSwitchSupported
model: root.connectionTypes.map(t => root.typeLabels[t] || t)
currentIndex: Math.max(0, root.connectionTypes.indexOf(root.currentConnectionType))
selectionMode: "single"
onSelectionChanged: (index, selected) => {
if (!selected)
return;
root.selectedType = root.connectionTypes[index] || "wifi";
NetworkService.setNetworkPreference(root.selectedType);
}
}
@@ -122,7 +122,7 @@ Item {
Row {
width: parent.width
spacing: Theme.spacingM
visible: NetworkService.backend === "networkmanager" && [NetworkService.ethernetConnected, NetworkService.wifiConnected, NetworkService.cellularConnected].filter(v => v).length > 1
visible: NetworkService.backend === "networkmanager" && [NetworkService.ethernetDevices, NetworkService.wifiDevices, NetworkService.cellularDevices].filter(d => (d?.length ?? 0) > 0).length > 1
StyledText {
text: I18n.tr("Preference", "noun, which network connection type is preferred")
+7 -19
View File
@@ -537,8 +537,8 @@ Singleton {
log.info("Successfully connected to", pendingConnectionSSID, "in", elapsed, "ms");
ToastService.showInfo(I18n.tr("Connected to %1", "wifi toast, %1 is the network name").arg(pendingConnectionSSID));
if (userPreference === "wifi" || userPreference === "auto") {
setConnectionPriority("wifi");
if (userPreference === "wifi") {
applyNetworkPreference("wifi");
}
pendingConnectionSSID = "";
@@ -864,10 +864,13 @@ Singleton {
function setNetworkPreference(preference) {
if (!networkAvailable)
return;
SettingsData.set("networkPreference", preference);
applyNetworkPreference(preference);
}
function applyNetworkPreference(preference) {
changingPreference = true;
targetPreference = preference;
SettingsData.set("networkPreference", preference);
DMSService.sendRequest("network.preference.set", {
preference: preference
}, response => {
@@ -880,21 +883,6 @@ Singleton {
});
}
function setConnectionPriority(type) {
if (type === "wifi") {
setNetworkPreference("wifi");
} else if (type === "ethernet") {
setNetworkPreference("ethernet");
} else if (type === "cellular") {
setNetworkPreference("cellular");
}
}
function connectToWifiAndSetPreference(ssid, password, username = "", anonymousIdentity = "", domainSuffixMatch = "", hidden = false, eapMethod = "", phase2Auth = "") {
connectToWifi(ssid, password, username, anonymousIdentity, domainSuffixMatch, hidden, eapMethod, phase2Auth);
setNetworkPreference("wifi");
}
function toggleNetworkConnection(type) {
if (!networkAvailable)
return;
-12
View File
@@ -253,18 +253,6 @@ Singleton {
}
}
function setConnectionPriority(type) {
if (activeService && activeService.setConnectionPriority) {
activeService.setConnectionPriority(type);
}
}
function connectToWifiAndSetPreference(ssid, password, username = "", anonymousIdentity = "", domainSuffixMatch = "", hidden = false, eapMethod = "", phase2Auth = "") {
if (activeService && activeService.connectToWifiAndSetPreference) {
activeService.connectToWifiAndSetPreference(ssid, password, username, anonymousIdentity, domainSuffixMatch, hidden, eapMethod, phase2Auth);
}
}
function toggleNetworkConnection(type) {
if (activeService && activeService.toggleNetworkConnection) {
activeService.toggleNetworkConnection(type);