ifcfg-rh: preserve an empty tc configuration

If the TC setting contains no qdiscs and filters, it is lost after a
write-read cycle. Fix this by adding a new property to indicate the
presence of the (empty) setting.
This commit is contained in:
Beniamino Galvani 2021-05-25 18:00:27 +02:00
parent a48edd0410
commit 6a88d4e55c
8 changed files with 128 additions and 26 deletions

View File

@ -3432,6 +3432,7 @@ EXTRA_DIST += \
src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected \
src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc \
src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected \
src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected \
src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 \
src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 \
src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-invalid \

View File

@ -2706,7 +2706,8 @@ make_tc_setting(shvarFile *ifcfg)
}
if (nm_setting_tc_config_get_num_qdiscs(s_tc) > 0
|| nm_setting_tc_config_get_num_tfilters(s_tc) > 0)
|| nm_setting_tc_config_get_num_tfilters(s_tc) > 0
|| svGetValueBoolean(ifcfg, "TC_COMMIT", FALSE))
return NM_SETTING(s_tc);
g_object_unref(s_tc);

View File

@ -1042,6 +1042,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = {
_KEY_TYPE("STABLE_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("STP", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("SUBCHANNELS", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("TC_COMMIT", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("TEAM_CONFIG", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("TEAM_MASTER", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("TEAM_MASTER_UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN),

View File

@ -33,7 +33,7 @@ typedef struct {
NMSIfcfgKeyTypeFlags key_flags;
} NMSIfcfgKeyTypeInfo;
extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[248];
extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[249];
const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx);

View File

@ -2520,46 +2520,46 @@ write_sriov_setting(NMConnection *connection, shvarFile *ifcfg)
}
}
static gboolean
write_tc_setting(NMConnection *connection, shvarFile *ifcfg, GError **error)
static void
write_tc_setting(NMConnection *connection, shvarFile *ifcfg)
{
NMSettingTCConfig *s_tc;
guint i, num, n;
guint num_qdiscs;
guint num_filters;
guint i;
guint n;
char tag[64];
s_tc = nm_connection_get_setting_tc_config(connection);
if (!s_tc)
return TRUE;
return;
num = nm_setting_tc_config_get_num_qdiscs(s_tc);
for (n = 1, i = 0; i < num; i++) {
num_qdiscs = nm_setting_tc_config_get_num_qdiscs(s_tc);
for (n = 1, i = 0; i < num_qdiscs; i++) {
NMTCQdisc * qdisc;
gs_free char *str = NULL;
qdisc = nm_setting_tc_config_get_qdisc(s_tc, i);
str = nm_utils_tc_qdisc_to_str(qdisc, error);
if (!str)
return FALSE;
str = nm_utils_tc_qdisc_to_str(qdisc, NULL);
nm_assert(str);
svSetValueStr(ifcfg, numbered_tag(tag, "QDISC", n), str);
n++;
}
num = nm_setting_tc_config_get_num_tfilters(s_tc);
for (n = 1, i = 0; i < num; i++) {
num_filters = nm_setting_tc_config_get_num_tfilters(s_tc);
for (n = 1, i = 0; i < num_filters; i++) {
NMTCTfilter * tfilter;
gs_free char *str = NULL;
tfilter = nm_setting_tc_config_get_tfilter(s_tc, i);
str = nm_utils_tc_tfilter_to_str(tfilter, error);
if (!str)
return FALSE;
str = nm_utils_tc_tfilter_to_str(tfilter, NULL);
nm_assert(str);
svSetValueStr(ifcfg, numbered_tag(tag, "FILTER", n), str);
n++;
}
return TRUE;
if (num_qdiscs == 0 && num_filters == 0)
svSetValueBoolean(ifcfg, "TC_COMMIT", TRUE);
}
static void
@ -3382,9 +3382,7 @@ do_write_construct(NMConnection * connection,
write_match_setting(connection, ifcfg);
write_hostname_setting(connection, ifcfg);
write_sriov_setting(connection, ifcfg);
if (!write_tc_setting(connection, ifcfg, error))
return FALSE;
write_tc_setting(connection, ifcfg);
route_path_is_svformat = utils_has_route_file_new_syntax(route_path);

View File

@ -0,0 +1,15 @@
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
TC_COMMIT=yes
BOOTPROTO=none
IPADDR=1.1.1.3
PREFIX=24
GATEWAY=1.1.1.1
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=no
NAME="Test Write TC config"
UUID=${UUID}
DEVICE=eth0
ONBOOT=yes

View File

@ -11141,6 +11141,85 @@ test_tc_read(void)
g_object_unref(connection);
}
static void
test_tc_write_empty(void)
{
nmtst_auto_unlinkfile char *testfile = NULL;
gs_unref_object NMConnection *connection = NULL;
gs_unref_object NMConnection *reread = NULL;
NMSettingConnection * s_con;
NMSettingIPConfig * s_ip4;
NMSettingIPConfig * s_ip6;
NMSettingWired * s_wired;
NMSettingTCConfig * s_tc;
NMIPAddress * addr;
GError * error = NULL;
connection = nm_simple_connection_new();
/* Connection setting */
s_con = (NMSettingConnection *) nm_setting_connection_new();
nm_connection_add_setting(connection, NM_SETTING(s_con));
g_object_set(s_con,
NM_SETTING_CONNECTION_ID,
"Test Write TC config",
NM_SETTING_CONNECTION_UUID,
nm_uuid_generate_random_str_a(),
NM_SETTING_CONNECTION_AUTOCONNECT,
TRUE,
NM_SETTING_CONNECTION_INTERFACE_NAME,
"eth0",
NM_SETTING_CONNECTION_TYPE,
NM_SETTING_WIRED_SETTING_NAME,
NULL);
/* Wired setting */
s_wired = (NMSettingWired *) nm_setting_wired_new();
nm_connection_add_setting(connection, NM_SETTING(s_wired));
/* IP4 setting */
s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new();
nm_connection_add_setting(connection, NM_SETTING(s_ip4));
g_object_set(s_ip4,
NM_SETTING_IP_CONFIG_METHOD,
NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
NM_SETTING_IP_CONFIG_GATEWAY,
"1.1.1.1",
NM_SETTING_IP_CONFIG_MAY_FAIL,
TRUE,
NULL);
addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error);
g_assert_no_error(error);
nm_setting_ip_config_add_address(s_ip4, addr);
nm_ip_address_unref(addr);
/* IP6 setting */
s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new();
nm_connection_add_setting(connection, NM_SETTING(s_ip6));
g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);
/* TC setting */
s_tc = (NMSettingTCConfig *) nm_setting_tc_config_new();
nm_connection_add_setting(connection, NM_SETTING(s_tc));
nm_connection_add_setting(connection, nm_setting_proxy_new());
nmtst_assert_connection_verifies_without_normalization(connection);
_writer_new_connec_exp(connection,
TEST_SCRATCH_DIR,
TEST_IFCFG_DIR "/ifcfg-test-tc-write-empty.cexpected",
&testfile);
reread = _connection_from_file(testfile, NULL, TYPE_BOND, NULL);
nmtst_assert_connection_equals(connection, FALSE, reread, FALSE);
}
static void
test_tc_write(void)
{
@ -11883,6 +11962,7 @@ main(int argc, char **argv)
g_test_add_func(TPATH "tc/read", test_tc_read);
g_test_add_func(TPATH "tc/write", test_tc_write);
g_test_add_func(TPATH "tc/write_empty", test_tc_write_empty);
g_test_add_func(TPATH "utils/test_well_known_keys", test_well_known_keys);
g_test_add_func(TPATH "utils/test_utils_has_route_file_new_syntax",
test_utils_has_route_file_new_syntax);

View File

@ -1822,8 +1822,11 @@ nm_setting_tc_config_class_init(NMSettingTCConfigClass *klass)
**/
/* ---ifcfg-rh---
* property: qdiscs
* variable: QDISC1(+), QDISC2(+), ...
* description: Queueing disciplines
* variable: QDISC1(+), QDISC2(+), ..., TC_COMMIT(+)
* description: Queueing disciplines to set on the interface. When no
* QDISC1, QDISC2, ..., FILTER1, FILTER2, ... keys are present,
* NetworkManager doesn't touch qdiscs and filters present on the
* interface, unless TC_COMMIT is set to 'yes'.
* example: QDISC1=ingress, QDISC2="root handle 1234: fq_codel"
* ---end---
*/
@ -1853,8 +1856,11 @@ nm_setting_tc_config_class_init(NMSettingTCConfigClass *klass)
**/
/* ---ifcfg-rh---
* property: qdiscs
* variable: FILTER1(+), FILTER2(+), ...
* description: Traffic filters
* variable: FILTER1(+), FILTER2(+), ..., TC_COMMIT(+)
* description: Traffic filters to set on the interface. When no
* QDISC1, QDISC2, ..., FILTER1, FILTER2, ... keys are present,
* NetworkManager doesn't touch qdiscs and filters present on the
* interface, unless TC_COMMIT is set to 'yes'.
* example: FILTER1="parent ffff: matchall action simple sdata Input", ...
* ---end---
*/