nmcli: accept certain IP settings on port connections
Commit bb850fda0e
('nmcli: connection: process port-type, type
and controller first') started correctly rejecting IP configuration
on port connections.
However, previously nmcli would accept IP parameters for ports when
using a specific parameters order. To avoid breaking user scripts that
may have relied on this behavior, introduce a backward compatibility
quirk.
Specifically, nmcli accepts a disabled/ignore IP method on a port
connection. For any other IP setting on a port connection, a specific
error message is now shown.
https://issues.redhat.com/browse/RHEL-90756
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2227
This commit is contained in:
@@ -5266,6 +5266,45 @@ _copy_connection_properties(const char ***dst,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
is_ip_setting_for_port_connection(NMConnection *connection,
|
||||||
|
const char *setting_name,
|
||||||
|
const char *property_name,
|
||||||
|
const char *value,
|
||||||
|
gboolean *out_is_method_disabled)
|
||||||
|
{
|
||||||
|
NMSettingConnection *s_con;
|
||||||
|
|
||||||
|
*out_is_method_disabled = FALSE;
|
||||||
|
|
||||||
|
if (!NM_IN_STRSET(setting_name,
|
||||||
|
NM_SETTING_IP4_CONFIG_SETTING_NAME,
|
||||||
|
NM_SETTING_IP6_CONFIG_SETTING_NAME))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
s_con = nm_connection_get_setting_connection(connection);
|
||||||
|
if (!s_con)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!nm_setting_connection_get_controller(s_con))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (nm_streq(property_name, NM_SETTING_IP_CONFIG_METHOD)) {
|
||||||
|
if (nm_streq(setting_name, NM_SETTING_IP4_CONFIG_SETTING_NAME)) {
|
||||||
|
if (nm_streq(value, NM_SETTING_IP4_CONFIG_METHOD_DISABLED))
|
||||||
|
*out_is_method_disabled = TRUE;
|
||||||
|
} else {
|
||||||
|
/* IPv6 */
|
||||||
|
if (NM_IN_STRSET(value,
|
||||||
|
NM_SETTING_IP6_CONFIG_METHOD_DISABLED,
|
||||||
|
NM_SETTING_IP6_CONFIG_METHOD_IGNORE))
|
||||||
|
*out_is_method_disabled = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
nmc_process_connection_properties(NmCli *nmc,
|
nmc_process_connection_properties(NmCli *nmc,
|
||||||
NMConnection *connection,
|
NMConnection *connection,
|
||||||
@@ -5428,24 +5467,58 @@ nmc_process_connection_properties(NmCli *nmc,
|
|||||||
if (argc == 1 && nmc->complete)
|
if (argc == 1 && nmc->complete)
|
||||||
complete_property_name(nmc, connection, modifier, option_sett, option_prop);
|
complete_property_name(nmc, connection, modifier, option_sett, option_prop);
|
||||||
|
|
||||||
option_sett_expanded =
|
|
||||||
check_valid_name(option_sett, type_settings, port_settings, &local);
|
|
||||||
if (!option_sett_expanded) {
|
|
||||||
g_set_error(error,
|
|
||||||
NMCLI_ERROR,
|
|
||||||
NMC_RESULT_ERROR_USER_INPUT,
|
|
||||||
_("Error: invalid or not allowed setting '%s': %s."),
|
|
||||||
option_sett,
|
|
||||||
local->message);
|
|
||||||
g_clear_error(&local);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
if (!get_value(&value, &argc, &argv, option_orig, error))
|
if (!get_value(&value, &argc, &argv, option_orig, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
option_sett_expanded =
|
||||||
|
check_valid_name(option_sett, type_settings, port_settings, &local);
|
||||||
|
if (!option_sett_expanded) {
|
||||||
|
gboolean raise_error = TRUE;
|
||||||
|
gboolean is_method_disabled = FALSE;
|
||||||
|
|
||||||
|
/* The setting does not exist or is now allowed for the given
|
||||||
|
* connection type or for the given port type. In the past nmcli
|
||||||
|
* accepted IP-config properties for port connections under some
|
||||||
|
* circumstances. For backward bug compatibility, still allow
|
||||||
|
* the user to set the IP method to disabled/ignore for ports,
|
||||||
|
* so that we don't break user scripts.
|
||||||
|
* */
|
||||||
|
if (is_ip_setting_for_port_connection(connection,
|
||||||
|
option_sett,
|
||||||
|
option_prop,
|
||||||
|
value,
|
||||||
|
&is_method_disabled)) {
|
||||||
|
if (is_method_disabled) {
|
||||||
|
/* Allowed */
|
||||||
|
option_sett_expanded = option_sett;
|
||||||
|
raise_error = FALSE;
|
||||||
|
g_clear_error(&local);
|
||||||
|
} else {
|
||||||
|
/* The property is not a disabled/ignore IP method. Raise a
|
||||||
|
* meaningful error, instead of the generic "setting X is not
|
||||||
|
* among LIST" */
|
||||||
|
g_clear_error(&local);
|
||||||
|
g_set_error(&local,
|
||||||
|
NMCLI_ERROR,
|
||||||
|
NMC_RESULT_ERROR_USER_INPUT,
|
||||||
|
_("port connections cannot have IP configuration"));
|
||||||
|
raise_error = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (raise_error) {
|
||||||
|
g_set_error(error,
|
||||||
|
NMCLI_ERROR,
|
||||||
|
NMC_RESULT_ERROR_USER_INPUT,
|
||||||
|
_("Error: invalid or not allowed setting '%s': %s."),
|
||||||
|
option_sett,
|
||||||
|
local->message);
|
||||||
|
g_clear_error(&local);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!argc && nmc->complete) {
|
if (!argc && nmc->complete) {
|
||||||
complete_property(nmc, option_sett, option_prop, value ?: "", connection);
|
complete_property(nmc, option_sett, option_prop, value ?: "", connection);
|
||||||
break;
|
break;
|
||||||
|
@@ -57981,3 +57981,43 @@ con-xx2 UUID-con-xx2-REPLACED-REPLACED-REPLA ethernet 0 nigdy
|
|||||||
con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet 0 nigdy tak 0 nie /org/freedesktop/NetworkManager/Settings/Connection/1 nie -- -- -- -- /etc/NetworkManager/system-connections/con-1
|
con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet 0 nigdy tak 0 nie /org/freedesktop/NetworkManager/Settings/Connection/1 nie -- -- -- -- /etc/NetworkManager/system-connections/con-1
|
||||||
|
|
||||||
<<<
|
<<<
|
||||||
|
size: 359
|
||||||
|
location: src/tests/client/test-client.py:test_004()/934
|
||||||
|
cmd: $NMCLI connection add type ethernet ifname foobar con-name con-port1 ipv4.method disabled ipv6.method ignore connection.port-type bridge connection.controller bridge1
|
||||||
|
lang: C
|
||||||
|
returncode: 0
|
||||||
|
stdout: 82 bytes
|
||||||
|
>>>
|
||||||
|
Connection 'con-port1' (UUID-con-port1-REPLACED-REPLACED-REP) successfully added.
|
||||||
|
|
||||||
|
<<<
|
||||||
|
size: 353
|
||||||
|
location: src/tests/client/test-client.py:test_004()/935
|
||||||
|
cmd: $NMCLI connection add type ethernet ifname foobar con-name ethernet-foobar ipv6.method auto connection.port-type bridge connection.controller bridge1
|
||||||
|
lang: C
|
||||||
|
returncode: 2
|
||||||
|
stderr: 93 bytes
|
||||||
|
>>>
|
||||||
|
Error: invalid or not allowed setting 'ipv6': port connections cannot have IP configuration.
|
||||||
|
|
||||||
|
<<<
|
||||||
|
size: 373
|
||||||
|
location: src/tests/client/test-client.py:test_004()/936
|
||||||
|
cmd: $NMCLI connection add type ovs-interface ifname ovs-int con-name con-ovs-int ipv4.method auto ipv6.method link-local connection.port-type ovs-port connection.controller ovs-port1
|
||||||
|
lang: C
|
||||||
|
returncode: 0
|
||||||
|
stdout: 84 bytes
|
||||||
|
>>>
|
||||||
|
Connection 'con-ovs-int' (UUID-con-ovs-int-REPLACED-REPLACED-R) successfully added.
|
||||||
|
|
||||||
|
<<<
|
||||||
|
size: 377
|
||||||
|
location: src/tests/client/test-client.py:test_004()/937
|
||||||
|
cmd: $NMCLI connection add type ethernet ifname enp1s0 con-name con-port2 ipv4.method manual ipv4.addresses 192.0.2.1/24 ipv6.method dhcp connection.port-type vrf connection.controller vrf1
|
||||||
|
lang: C
|
||||||
|
returncode: 0
|
||||||
|
stdout: 82 bytes
|
||||||
|
>>>
|
||||||
|
Connection 'con-port2' (UUID-con-port2-REPLACED-REPLACED-REP) successfully added.
|
||||||
|
|
||||||
|
<<<
|
||||||
|
@@ -2125,6 +2125,113 @@ class TestNmcli(unittest.TestCase):
|
|||||||
replace_stdout=replace_uuids,
|
replace_stdout=replace_uuids,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# It is allowed to set IP method disabled/ignore for ports
|
||||||
|
replace_uuids.append(
|
||||||
|
self.ctx.srv.ReplaceTextConUuid(
|
||||||
|
"con-port1", "UUID-con-port1-REPLACED-REPLACED-REP"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.call_nmcli(
|
||||||
|
[
|
||||||
|
"connection",
|
||||||
|
"add",
|
||||||
|
"type",
|
||||||
|
"ethernet",
|
||||||
|
"ifname",
|
||||||
|
"foobar",
|
||||||
|
"con-name",
|
||||||
|
"con-port1",
|
||||||
|
"ipv4.method",
|
||||||
|
"disabled",
|
||||||
|
"ipv6.method",
|
||||||
|
"ignore",
|
||||||
|
"connection.port-type",
|
||||||
|
"bridge",
|
||||||
|
"connection.controller",
|
||||||
|
"bridge1",
|
||||||
|
],
|
||||||
|
replace_stdout=replace_uuids,
|
||||||
|
)
|
||||||
|
|
||||||
|
# It is NOT allowed to set IP method != disabled/ignore for ports
|
||||||
|
self.call_nmcli(
|
||||||
|
[
|
||||||
|
"connection",
|
||||||
|
"add",
|
||||||
|
"type",
|
||||||
|
"ethernet",
|
||||||
|
"ifname",
|
||||||
|
"foobar",
|
||||||
|
"con-name",
|
||||||
|
"ethernet-foobar",
|
||||||
|
"ipv6.method",
|
||||||
|
"auto",
|
||||||
|
"connection.port-type",
|
||||||
|
"bridge",
|
||||||
|
"connection.controller",
|
||||||
|
"bridge1",
|
||||||
|
],
|
||||||
|
replace_stdout=replace_uuids,
|
||||||
|
)
|
||||||
|
|
||||||
|
# ovs-interface connections support IP configuration
|
||||||
|
replace_uuids.append(
|
||||||
|
self.ctx.srv.ReplaceTextConUuid(
|
||||||
|
"con-ovs-int", "UUID-con-ovs-int-REPLACED-REPLACED-R"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.call_nmcli(
|
||||||
|
[
|
||||||
|
"connection",
|
||||||
|
"add",
|
||||||
|
"type",
|
||||||
|
"ovs-interface",
|
||||||
|
"ifname",
|
||||||
|
"ovs-int",
|
||||||
|
"con-name",
|
||||||
|
"con-ovs-int",
|
||||||
|
"ipv4.method",
|
||||||
|
"auto",
|
||||||
|
"ipv6.method",
|
||||||
|
"link-local",
|
||||||
|
"connection.port-type",
|
||||||
|
"ovs-port",
|
||||||
|
"connection.controller",
|
||||||
|
"ovs-port1",
|
||||||
|
],
|
||||||
|
replace_stdout=replace_uuids,
|
||||||
|
)
|
||||||
|
|
||||||
|
# VRF ports support IP configuration
|
||||||
|
replace_uuids.append(
|
||||||
|
self.ctx.srv.ReplaceTextConUuid(
|
||||||
|
"con-port2", "UUID-con-port2-REPLACED-REPLACED-REP"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.call_nmcli(
|
||||||
|
[
|
||||||
|
"connection",
|
||||||
|
"add",
|
||||||
|
"type",
|
||||||
|
"ethernet",
|
||||||
|
"ifname",
|
||||||
|
"enp1s0",
|
||||||
|
"con-name",
|
||||||
|
"con-port2",
|
||||||
|
"ipv4.method",
|
||||||
|
"manual",
|
||||||
|
"ipv4.addresses",
|
||||||
|
"192.0.2.1/24",
|
||||||
|
"ipv6.method",
|
||||||
|
"dhcp",
|
||||||
|
"connection.port-type",
|
||||||
|
"vrf",
|
||||||
|
"connection.controller",
|
||||||
|
"vrf1",
|
||||||
|
],
|
||||||
|
replace_stdout=replace_uuids,
|
||||||
|
)
|
||||||
|
|
||||||
@nm_test_no_dbus
|
@nm_test_no_dbus
|
||||||
def test_offline(self):
|
def test_offline(self):
|
||||||
# Make sure we're not using D-Bus
|
# Make sure we're not using D-Bus
|
||||||
|
@@ -613,6 +613,7 @@ class NmUtil:
|
|||||||
if t not in [
|
if t not in [
|
||||||
NM.SETTING_GSM_SETTING_NAME,
|
NM.SETTING_GSM_SETTING_NAME,
|
||||||
NM.SETTING_MACVLAN_SETTING_NAME,
|
NM.SETTING_MACVLAN_SETTING_NAME,
|
||||||
|
NM.SETTING_OVS_INTERFACE_SETTING_NAME,
|
||||||
NM.SETTING_VLAN_SETTING_NAME,
|
NM.SETTING_VLAN_SETTING_NAME,
|
||||||
NM.SETTING_VPN_SETTING_NAME,
|
NM.SETTING_VPN_SETTING_NAME,
|
||||||
NM.SETTING_WIMAX_SETTING_NAME,
|
NM.SETTING_WIMAX_SETTING_NAME,
|
||||||
|
Reference in New Issue
Block a user