From 5cbe512fd326a6002eb18101ffc5609713f0c663 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Wed, 15 Nov 2017 15:47:29 +0100 Subject: [PATCH 01/23] libnm-core: preserve keys order in team.config with old jansson libs When jansson lib version is < 2.8 the order of the keys of json objects is not preserved automatically. In particular, when loading the json string, parsing it and dumping it back to a string the key order will be lost if the now deprecated JSON_PRESERVE_ORDER flag is not set. Add the flag: will do nothing on recent jansson versions but will fix behavior for legacy ones. (cherry picked from commit 5e6f7de4be4a1b606d77b1766663fbfd9f40c6d7) --- libnm-core/nm-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index a31744df0c..b150521c2e 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4728,7 +4728,7 @@ _nm_utils_team_config_set (char **conf, done: if (updated) { g_free (*conf); - *conf = json_dumps (json, 0); + *conf = json_dumps (json, JSON_PRESERVE_ORDER); /* Don't save an empty config */ if (nm_streq0 (*conf, "{}")) { g_free (*conf); From 000e02f56aa68cb2ded3d23175e6fc221e9cc994 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Mon, 13 Nov 2017 18:33:34 +0100 Subject: [PATCH 02/23] ifcfg-rh: tests: align json team configuration format to jansson one (cherry picked from commit 53821a4b136fab2b8a40f109c54d2d396055591b) --- ...ifcfg-Test_Write_Team_Infiniband_Port.cexpected | 2 +- .../ifcfg-Test_Write_Team_Port.cexpected | 2 +- .../tests/network-scripts/ifcfg-test-team-master-1 | 2 +- .../tests/network-scripts/ifcfg-test-team-master-2 | 2 +- .../tests/network-scripts/ifcfg-test-team-port-1 | 2 +- .../tests/network-scripts/ifcfg-test-team-port-2 | 2 +- .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 14 ++++++++------ 7 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected index 460278e1eb..2df1fbb38b 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected @@ -1,6 +1,6 @@ CONNECTED_MODE=no TYPE=InfiniBand -TEAM_PORT_CONFIG="{ \"inf1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"inf1\": {\"prio\": -10, \"sticky\": true}}" NAME="Test Write Team Infiniband Port" UUID=${UUID} DEVICE=inf1 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected index 0b1deb8077..ff55cefe7f 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected @@ -1,4 +1,4 @@ -TEAM_PORT_CONFIG="{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"p4p1\": {\"prio\": -10, \"sticky\": true}}" NAME="Test Write Team Port" UUID=${UUID} ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 index 7edc736af0..209447b844 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 @@ -2,5 +2,5 @@ DEVICE=team0 ONBOOT=no DEVICETYPE=Team BOOTPROTO=dhcp -TEAM_CONFIG="{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }" +TEAM_CONFIG="{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 index d01e37c552..26e448cc7e 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 @@ -1,5 +1,5 @@ DEVICE=team0 ONBOOT=no BOOTPROTO=dhcp -TEAM_CONFIG="{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }" +TEAM_CONFIG="{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 index 966bec6777..80355c2643 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 @@ -1,5 +1,5 @@ TYPE=Ethernet -TEAM_PORT_CONFIG="{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"p4p1\": {\"prio\": -10, \"sticky\": true}}" DEVICE=p4p1 TEAM_MASTER=team0 DEVICETYPE=TeamPort diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 index 992510ee0a..4284737a1c 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 @@ -1,4 +1,4 @@ TYPE=Ethernet -TEAM_PORT_CONFIG="{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"p4p1\": {\"prio\": -10, \"sticky\": true}}" DEVICE=p4p1 TEAM_MASTER=team0 diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 6510136fc3..6bf2755613 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -8695,7 +8695,7 @@ test_read_team_master (gconstpointer user_data) NMConnection *connection; NMSettingConnection *s_con; NMSettingTeam *s_team; - const char *expected_config = "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"; + const char *expected_config = "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}"; connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL); @@ -8748,7 +8748,7 @@ test_write_team_master (void) NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; - const char *expected_config = "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"; + const char *expected_config = "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}"; shvarFile *f; connection = nm_simple_connection_new (); @@ -8817,7 +8817,7 @@ test_read_team_port (gconstpointer user_data) NMConnection *connection; NMSettingConnection *s_con; NMSettingTeamPort *s_team_port; - const char *expected_config = "{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }"; + const char *expected_config = "{\"p4p1\": {\"prio\": -10, \"sticky\": true}}"; connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL); @@ -8842,7 +8842,7 @@ test_write_team_port (void) NMSettingConnection *s_con; NMSettingTeamPort *s_team_port; NMSettingWired *s_wired; - const char *expected_config = "{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }"; + const char *expected_config = "{\"p4p1\": {\"prio\": -10, \"sticky\": true}}"; shvarFile *f; connection = nm_simple_connection_new (); @@ -8897,7 +8897,7 @@ test_write_team_infiniband_port (void) NMSettingConnection *s_con; NMSettingTeamPort *s_team_port; NMSettingInfiniband *s_inf; - const char *expected_config = "{ \"inf1\": { \"prio\": -10, \"sticky\": true } }"; + const char *expected_config = "{\"inf1\": {\"prio\": -10, \"sticky\": true}}"; shvarFile *f; connection = nm_simple_connection_new (); @@ -9258,7 +9258,9 @@ test_svUnescape (void) V0 ("Bob outside LAN", NULL), V1 ("x", "x"), V1 ("'{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }'", - "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"), + "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"), + V1 ("'{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}'", + "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}"), V1 ("x\"\"b", "xb"), V1 ("x\"c\"b", "xcb"), V1 ("\"c\"b", "cb"), From e9d5836937d5c576a50d4b7916e664ecb2b4bb28 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Thu, 2 Nov 2017 17:13:46 +0100 Subject: [PATCH 03/23] libnm-core: team: add NMTeamLinkWatcher boxed type Team allows to specify multiple link watchers for each link. Define a link watcher object in order to allow to specify multiple ones for each Team configuration. (cherry picked from commit 72f6d08714f19598eedd5b9d96f032dce0e80c8b) --- libnm-core/nm-setting-team.c | 527 +++++++++++++++++++++++++++++++++++ libnm-core/nm-setting-team.h | 75 +++++ libnm/libnm.ver | 18 ++ 3 files changed, 620 insertions(+) diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c index 75e47f3859..b14094a026 100644 --- a/libnm-core/nm-setting-team.c +++ b/libnm-core/nm-setting-team.c @@ -15,6 +15,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * + * Copyright 2017 Red Hat, Inc. * Copyright 2013 Jiri Pirko */ @@ -36,6 +37,532 @@ * necessary for team connections. **/ +/***************************************************************************** + * NMTeamLinkWatch + *****************************************************************************/ + +G_DEFINE_BOXED_TYPE (NMTeamLinkWatcher, nm_team_link_watcher, + nm_team_link_watcher_dup, nm_team_link_watcher_unref) + +enum LinkWatcherTypes { + LINK_WATCHER_ETHTOOL = 0, + LINK_WATCHER_NSNA_PING = 1, + LINK_WATCHER_ARP_PING = 2 +}; + +static const char* _link_watcher_name[] = { + [LINK_WATCHER_ETHTOOL] = NM_TEAM_LINK_WATCHER_ETHTOOL, + [LINK_WATCHER_NSNA_PING] = NM_TEAM_LINK_WATCHER_NSNA_PING, + [LINK_WATCHER_ARP_PING] = NM_TEAM_LINK_WATCHER_ARP_PING +}; + +struct NMTeamLinkWatcher { + guint refcount; + + guint8 type; /* LinkWatcherTypes */ + + /* + * The union is constructed in order to allow mapping the options of all the + * watchers on the arp_ping one: this would allow to manipulate all the watchers + * by using the arp_ping struct. See for instance the nm_team_link_watcher_unref() + * and nm_team_link_watcher_equal() functions. So, if you need to change the union + * be careful. + */ + union { + struct { + int delay_up; + int delay_down; + } ethtool; + struct { + int init_wait; + int interval; + int missed_max; + char *target_host; + } nsna_ping; + struct { + int init_wait; + int interval; + int missed_max; + char *target_host; + char *source_host; + NMTeamLinkWatcherArpPingFlags flags; + } arp_ping; + }; +}; + +#define _CHECK_WATCHER_VOID(watcher) \ + G_STMT_START { \ + g_return_if_fail (watcher != NULL); \ + g_return_if_fail (watcher->refcount > 0); \ + g_return_if_fail (watcher->type <= LINK_WATCHER_ARP_PING); \ + } G_STMT_END + +#define _CHECK_WATCHER(watcher, err_val) \ + G_STMT_START { \ + g_return_val_if_fail (watcher != NULL, err_val); \ + g_return_val_if_fail (watcher->refcount > 0, err_val); \ + g_return_val_if_fail (watcher->type <= LINK_WATCHER_ARP_PING, err_val); \ + } G_STMT_END + +/** + * nm_team_link_watcher_new_ethtool: + * @delay_up: delay_up value + * @delay_down: delay_down value + * @error: this call never fails, so this var is not used but kept for format + * consistency with the link_watcher constructors of other type + * + * Creates a new ethtool #NMTeamLinkWatcher object + * + * Returns: (transfer full): the new #NMTeamLinkWatcher object + * + * Since: 1.10.2 + **/ +NMTeamLinkWatcher * +nm_team_link_watcher_new_ethtool (gint delay_up, + gint delay_down, + GError **error) +{ + NMTeamLinkWatcher *watcher; + const char *val_fail = NULL; + + if (delay_up < 0 || delay_up > G_MAXINT32) + val_fail = "delay-up"; + if (delay_down < 0 || delay_down > G_MAXINT32) + val_fail = "delay-down"; + if (val_fail) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("%s is out of range [0, %d]"), val_fail, G_MAXINT32); + return NULL; + } + + watcher = g_slice_new0 (NMTeamLinkWatcher); + watcher->refcount = 1; + + watcher->type = LINK_WATCHER_ETHTOOL; + watcher->ethtool.delay_up = delay_up; + watcher->ethtool.delay_down = delay_down; + + return watcher; +} + +/** + * nm_team_link_watcher_new_nsna_ping: + * @init_wait: init_wait value + * @interval: interval value + * @missed_max: missed_max value + * @target_host: the host name or the ipv6 address that will be used as + * target address in the NS packet + * @error: (out) (allow-none): location to store the error on failure + * + * Creates a new nsna_ping #NMTeamLinkWatcher object + * + * Returns: (transfer full): the new #NMTeamLinkWatcher object, or %NULL on error + * + * Since: 1.10.2 + **/ +NMTeamLinkWatcher * +nm_team_link_watcher_new_nsna_ping (gint init_wait, + gint interval, + gint missed_max, + const char *target_host, + GError **error) +{ + NMTeamLinkWatcher *watcher; + gs_strfreev gchar **strv = NULL; + const char *val_fail = NULL; + + if (!target_host) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("Missing target-host in nsna_ping link watcher")); + return NULL; + } + + strv = g_strsplit_set (target_host, " \\/\t=\"\'", 0); + if (strv[1]) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("target-host '%s' contains invalid characters"), target_host); + return NULL; + } + + if (init_wait < 0 || init_wait > G_MAXINT32) + val_fail = "init-wait"; + if (interval < 0 || interval > G_MAXINT32) + val_fail = "interval"; + if (missed_max < 0 || missed_max > G_MAXINT32) + val_fail = "missed-max"; + if (val_fail) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("%s is out of range [0, %d]"), val_fail, G_MAXINT32); + return NULL; + } + + watcher = g_slice_new0 (NMTeamLinkWatcher); + watcher->refcount = 1; + + watcher->type = LINK_WATCHER_NSNA_PING; + watcher->nsna_ping.init_wait = init_wait; + watcher->nsna_ping.interval = interval; + watcher->nsna_ping.missed_max = missed_max; + watcher->nsna_ping.target_host = g_strdup (target_host); + + return watcher; +} + +/** + * nm_team_link_watcher_new_arp_ping: + * @init_wait: init_wait value + * @interval: interval value + * @missed_max: missed_max value + * @target_host: the host name or the ip address that will be used as destination + * address in the arp request + * @source_host: the host name or the ip address that will be used as source + * address in the arp request + * @flags: the watcher #NMTeamLinkWatcherArpPingFlags + * @error: (out) (allow-none): location to store the error on failure + * + * Creates a new arp_ping #NMTeamLinkWatcher object + * + * Returns: (transfer full): the new #NMTeamLinkWatcher object, or %NULL on error + * + * Since: 1.10.2 + **/ +NMTeamLinkWatcher * +nm_team_link_watcher_new_arp_ping (gint init_wait, + gint interval, + gint missed_max, + const char *target_host, + const char *source_host, + NMTeamLinkWatcherArpPingFlags flags, + GError **error) +{ + NMTeamLinkWatcher *watcher; + gs_strfreev gchar **strv = NULL; + const char *val_fail = NULL; + + if (!target_host || !source_host) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("Missing %s in arp_ping link watcher"), + target_host ? "source-host" : "target-host"); + return NULL; + } + + strv = g_strsplit_set (target_host, " \\/\t=\"\'", 0); + if (strv[1]) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("target-host '%s' contains invalid characters"), target_host); + return NULL; + } + g_strfreev (strv); + + strv = g_strsplit_set (source_host, " \\/\t=\"\'", 0); + if (strv[1]) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("source-host '%s' contains invalid characters"), source_host); + return NULL; + } + + if (init_wait < 0 || init_wait > G_MAXINT32) + val_fail = "init-wait"; + if (interval < 0 || interval > G_MAXINT32) + val_fail = "interval"; + if (missed_max < 0 || missed_max > G_MAXINT32) + val_fail = "missed-max"; + if (val_fail) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("%s is out of range [0, %d]"), val_fail, G_MAXINT32); + return NULL; + } + + watcher = g_slice_new0 (NMTeamLinkWatcher); + watcher->refcount = 1; + + watcher->type = LINK_WATCHER_ARP_PING; + watcher->arp_ping.init_wait = init_wait; + watcher->arp_ping.interval = interval; + watcher->arp_ping.missed_max = missed_max; + watcher->arp_ping.target_host = g_strdup (target_host); + watcher->arp_ping.source_host = g_strdup (source_host); + watcher->arp_ping.flags = flags; + + return watcher; +} + +/** + * nm_team_link_watcher_ref: + * @watcher: the #NMTeamLinkWatcher + * + * Increases the reference count of the object. + * + * Since: 1.10.2 + **/ +void +nm_team_link_watcher_ref (NMTeamLinkWatcher *watcher){ + _CHECK_WATCHER_VOID (watcher); + + watcher->refcount++; +} + +/** + * nm_team_link_watcher_unref: + * @watcher: the #NMTeamLinkWatcher + * + * Decreases the reference count of the object. If the reference count + * reaches zero, the object will be destroyed. + * + * Since: 1.10.2 + **/ +void +nm_team_link_watcher_unref (NMTeamLinkWatcher *watcher) +{ + _CHECK_WATCHER_VOID (watcher); + + watcher->refcount--; + if (watcher->refcount == 0) { + g_free (watcher->arp_ping.target_host); + g_free (watcher->arp_ping.source_host); + g_slice_free (NMTeamLinkWatcher, watcher); + } +} + +/** + * nm_team_link_watcher_equal: + * @watcher: the #NMTeamLinkWatcher + * @other: the #NMTeamLinkWatcher to compare @watcher to. + * + * Determines if two #NMTeamLinkWatcher objects contain the same values + * in all the properties. + * + * Returns: %TRUE if the objects contain the same values, %FALSE if they do not. + * + * Since: 1.10.2 + **/ +gboolean +nm_team_link_watcher_equal (NMTeamLinkWatcher *watcher, NMTeamLinkWatcher *other) +{ + _CHECK_WATCHER (watcher, FALSE); + _CHECK_WATCHER (other, FALSE); + + if ( watcher->type != other->type + || !nm_streq0 (watcher->arp_ping.target_host, other->arp_ping.target_host) + || !nm_streq0 (watcher->arp_ping.source_host, other->arp_ping.source_host) + || watcher->arp_ping.init_wait != other->arp_ping.init_wait + || watcher->arp_ping.interval != other->arp_ping.interval + || watcher->arp_ping.missed_max != other->arp_ping.missed_max + || watcher->arp_ping.flags != other->arp_ping.flags) + return FALSE; + + return TRUE; +} + +/** + * nm_team_link_watcher_dup: + * @watcher: the #NMTeamLinkWatcher + * + * Creates a copy of @watcher + * + * Returns: (transfer full): a copy of @watcher + * + * Since: 1.10.2 + **/ +NMTeamLinkWatcher * +nm_team_link_watcher_dup (NMTeamLinkWatcher *watcher) +{ + _CHECK_WATCHER (watcher, NULL); + + switch (watcher->type) { + case LINK_WATCHER_ETHTOOL: + return nm_team_link_watcher_new_ethtool (watcher->ethtool.delay_up, + watcher->ethtool.delay_down, + NULL); + break; + case LINK_WATCHER_NSNA_PING: + return nm_team_link_watcher_new_nsna_ping (watcher->nsna_ping.init_wait, + watcher->nsna_ping.interval, + watcher->nsna_ping.missed_max, + watcher->nsna_ping.target_host, + NULL); + break; + case LINK_WATCHER_ARP_PING: + return nm_team_link_watcher_new_arp_ping (watcher->arp_ping.init_wait, + watcher->arp_ping.interval, + watcher->arp_ping.missed_max, + watcher->arp_ping.target_host, + watcher->arp_ping.source_host, + watcher->arp_ping.flags, + NULL); + default: + g_assert_not_reached (); + return NULL; + } +} + +/** + * nm_team_link_watcher_get_name: + * @watcher: the #NMTeamLinkWatcher + * + * Gets the name of the link watcher to be used. + * + * Since: 1.10.2 + **/ +const char * +nm_team_link_watcher_get_name (NMTeamLinkWatcher *watcher) +{ + _CHECK_WATCHER (watcher, NULL); + + return _link_watcher_name[watcher->type]; +} + +/** + * nm_team_link_watcher_get_delay_up: + * @watcher: the #NMTeamLinkWatcher + * + * Gets the delay_up interval (in milliseconds) that elapses between the link + * coming up and the runner beeing notified about it. + * + * Since: 1.10.2 + **/ +int +nm_team_link_watcher_get_delay_up (NMTeamLinkWatcher *watcher) +{ + _CHECK_WATCHER (watcher, 0); + + if (watcher->type != LINK_WATCHER_ETHTOOL) + return -1; + return watcher->ethtool.delay_up; +} + +/** + * nm_team_link_watcher_get_delay_down: + * @watcher: the #NMTeamLinkWatcher + * + * Gets the delay_down interval (in milliseconds) that elapses between the link + * going down and the runner beeing notified about it. + * + * Since: 1.10.2 + **/ +int +nm_team_link_watcher_get_delay_down (NMTeamLinkWatcher *watcher) +{ + _CHECK_WATCHER (watcher, 0); + + if (watcher->type != LINK_WATCHER_ETHTOOL) + return -1; + return watcher->ethtool.delay_down; +} + +/** + * nm_team_link_watcher_get_init_wait: + * @watcher: the #NMTeamLinkWatcher + * + * Gets the init_wait interval (in milliseconds) that the team slave should + * wait before sending the first packet to the target host. + * + * Since: 1.10.2 + **/ +int +nm_team_link_watcher_get_init_wait (NMTeamLinkWatcher *watcher) +{ + _CHECK_WATCHER (watcher, 0); + + if (!NM_IN_SET (watcher->type, + LINK_WATCHER_NSNA_PING, + LINK_WATCHER_ARP_PING)) + return -1; + return watcher->arp_ping.init_wait; +} + +/** + * nm_team_link_watcher_get_interval: + * @watcher: the #NMTeamLinkWatcher + * + * Gets the interval (in milliseconds) that the team slave should wait between + * sending two check packets to the target host. + * + * Since: 1.10.2 + **/ +int +nm_team_link_watcher_get_interval (NMTeamLinkWatcher *watcher) +{ + _CHECK_WATCHER (watcher, 0); + + if (!NM_IN_SET (watcher->type, + LINK_WATCHER_NSNA_PING, + LINK_WATCHER_ARP_PING)) + return -1; + return watcher->arp_ping.interval; +} + +/** + * nm_team_link_watcher_get_missed_max: + * @watcher: the #NMTeamLinkWatcher + * + * Gets the number of missed replies after which the link is considered down. + * + * Since: 1.10.2 + **/ +int +nm_team_link_watcher_get_missed_max (NMTeamLinkWatcher *watcher) +{ + _CHECK_WATCHER (watcher, 0); + + if (!NM_IN_SET (watcher->type, + LINK_WATCHER_NSNA_PING, + LINK_WATCHER_ARP_PING)) + return -1; + return watcher->arp_ping.missed_max; +} + +/** + * nm_team_link_watcher_get_target_host: + * @watcher: the #NMTeamLinkWatcher + * + * Gets the host name/ip address to be used as destination for the link probing + * packets. + * + * Since: 1.10.2 + **/ +const char * +nm_team_link_watcher_get_target_host (NMTeamLinkWatcher *watcher) +{ + _CHECK_WATCHER (watcher, NULL); + + return watcher->arp_ping.target_host; +} + +/** + * nm_team_link_watcher_get_source_host: + * @watcher: the #NMTeamLinkWatcher + * + * Gets the ip address to be used as source for the link probing packets. + * + * Since: 1.10.2 + **/ +const char * +nm_team_link_watcher_get_source_host (NMTeamLinkWatcher *watcher) +{ + _CHECK_WATCHER (watcher, NULL); + + return watcher->arp_ping.source_host; +} + +/** + * nm_team_link_watcher_get_flags: + * @watcher: the #NMTeamLinkWatcher + * + * Gets the arp ping watcher flags. + * + * Since: 1.10.2 + **/ +NMTeamLinkWatcherArpPingFlags +nm_team_link_watcher_get_flags (NMTeamLinkWatcher *watcher) +{ + _CHECK_WATCHER (watcher, 0); + + return watcher->arp_ping.flags; +} + +/*****************************************************************************/ + G_DEFINE_TYPE_WITH_CODE (NMSettingTeam, nm_setting_team, NM_TYPE_SETTING, _nm_register_setting (TEAM, NM_SETTING_PRIORITY_HW_BASE)) NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_TEAM) diff --git a/libnm-core/nm-setting-team.h b/libnm-core/nm-setting-team.h index e3af68d4e7..aaaaee2c63 100644 --- a/libnm-core/nm-setting-team.h +++ b/libnm-core/nm-setting-team.h @@ -29,6 +29,80 @@ G_BEGIN_DECLS +/** + * NMTeamLinkWatcherArpPingFlags: + * @NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE: no one among the arp_ping link watcher + * boolean options ('validate_active', 'validate_inactive', 'send_always') is + * enabled (set to true). + * @NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE: the arp_ping link watcher + * option 'validate_active' is enabled (set to true). + * @NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE: the arp_ping link watcher + * option 'validate_inactive' is enabled (set to true). + * @NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS: the arp_ping link watcher option + * 'send_always' is enabled (set to true). + */ +typedef enum { /*< flags >*/ + NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE = 0, /*< skip >*/ + NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE = (1 << 1), + NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE = (1 << 2), + NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS = (1 << 3) +} NMTeamLinkWatcherArpPingFlags; + +#define NM_TEAM_LINK_WATCHER_ETHTOOL "ethtool" +#define NM_TEAM_LINK_WATCHER_ARP_PING "arp_ping" +#define NM_TEAM_LINK_WATCHER_NSNA_PING "nsna_ping" + + +typedef struct NMTeamLinkWatcher NMTeamLinkWatcher; + +GType nm_team_link_watcher_get_type (void); + +NM_AVAILABLE_IN_1_10_2 +NMTeamLinkWatcher *nm_team_link_watcher_new_ethtool (gint delay_up, + gint delay_down, + GError **error); +NM_AVAILABLE_IN_1_10_2 +NMTeamLinkWatcher *nm_team_link_watcher_new_nsna_ping (gint init_wait, + gint interval, + gint missed_max, + const char *target_host, + GError **error); +NM_AVAILABLE_IN_1_10_2 +NMTeamLinkWatcher *nm_team_link_watcher_new_arp_ping (gint init_wait, + gint interval, + gint missed_max, + const char *target_host, + const char *source_host, + NMTeamLinkWatcherArpPingFlags flags, + GError **error); +NM_AVAILABLE_IN_1_10_2 +void nm_team_link_watcher_ref (NMTeamLinkWatcher *watcher); +NM_AVAILABLE_IN_1_10_2 +void nm_team_link_watcher_unref (NMTeamLinkWatcher *watcher); +NM_AVAILABLE_IN_1_10_2 +gboolean nm_team_link_watcher_equal (NMTeamLinkWatcher *watcher, NMTeamLinkWatcher *other); +NM_AVAILABLE_IN_1_10_2 +NMTeamLinkWatcher *nm_team_link_watcher_dup (NMTeamLinkWatcher *watcher); +NM_AVAILABLE_IN_1_10_2 +const char *nm_team_link_watcher_get_name (NMTeamLinkWatcher *watcher); +NM_AVAILABLE_IN_1_10_2 +int nm_team_link_watcher_get_delay_up (NMTeamLinkWatcher *watcher); +NM_AVAILABLE_IN_1_10_2 +int nm_team_link_watcher_get_delay_down (NMTeamLinkWatcher *watcher); +NM_AVAILABLE_IN_1_10_2 +int nm_team_link_watcher_get_init_wait (NMTeamLinkWatcher *watcher); +NM_AVAILABLE_IN_1_10_2 +int nm_team_link_watcher_get_interval (NMTeamLinkWatcher *watcher); +NM_AVAILABLE_IN_1_10_2 +int nm_team_link_watcher_get_missed_max (NMTeamLinkWatcher *watcher); +NM_AVAILABLE_IN_1_10_2 +const char *nm_team_link_watcher_get_target_host (NMTeamLinkWatcher *watcher); +NM_AVAILABLE_IN_1_10_2 +const char *nm_team_link_watcher_get_source_host (NMTeamLinkWatcher *watcher); +NM_AVAILABLE_IN_1_10_2 +NMTeamLinkWatcherArpPingFlags nm_team_link_watcher_get_flags (NMTeamLinkWatcher *watcher); + + #define NM_TYPE_SETTING_TEAM (nm_setting_team_get_type ()) #define NM_SETTING_TEAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_TEAM, NMSettingTeam)) #define NM_SETTING_TEAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_TEAM, NMSettingTeamClass)) @@ -78,6 +152,7 @@ G_BEGIN_DECLS #define NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT 255 #define NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_LACP_PRIO + /** * NMSettingTeam: * diff --git a/libnm/libnm.ver b/libnm/libnm.ver index ad9615430b..63fa05df27 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1250,4 +1250,22 @@ global: nm_setting_team_remove_runner_tx_hash; nm_setting_team_remove_runner_tx_hash_by_value; nm_settings_update2_flags_get_type; + nm_team_link_watcher_arp_ping_flags_get_type; + nm_team_link_watcher_dup; + nm_team_link_watcher_equal; + nm_team_link_watcher_get_delay_down; + nm_team_link_watcher_get_delay_up; + nm_team_link_watcher_get_flags; + nm_team_link_watcher_get_init_wait; + nm_team_link_watcher_get_interval; + nm_team_link_watcher_get_missed_max; + nm_team_link_watcher_get_name; + nm_team_link_watcher_get_source_host; + nm_team_link_watcher_get_target_host; + nm_team_link_watcher_get_type; + nm_team_link_watcher_new_arp_ping; + nm_team_link_watcher_new_ethtool; + nm_team_link_watcher_new_nsna_ping; + nm_team_link_watcher_ref; + nm_team_link_watcher_unref; } libnm_1_10_0; From 574d70b2ebfb33e7a682fe29915eaae2bed76968 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Tue, 7 Nov 2017 14:38:45 +0100 Subject: [PATCH 04/23] libnm-core: add backend for GVariant de/serialization of link_watchers. (cherry picked from commit ba4ce843fa796c3e99777743279187b8c95b4743) --- libnm-core/nm-property-compare.c | 34 ++++++ libnm-core/nm-utils-private.h | 2 + libnm-core/nm-utils.c | 196 +++++++++++++++++++++++++++++++ libnm/generate-setting-docs.py | 1 + 4 files changed, 233 insertions(+) diff --git a/libnm-core/nm-property-compare.c b/libnm-core/nm-property-compare.c index d13d019f0a..64ed663c22 100644 --- a/libnm-core/nm-property-compare.c +++ b/libnm-core/nm-property-compare.c @@ -55,6 +55,38 @@ _nm_property_compare_collection (GVariant *value1, GVariant *value2) return 0; } +static gint +_nm_property_compare_vardict (GVariant *value1, GVariant *value2) +{ + GVariantIter iter; + int len1, len2; + const char *key; + GVariant *val1, *val2; + + len1 = g_variant_n_children (value1); + len2 = g_variant_n_children (value2); + + if (len1 != len2) + return len1 < len2 ? -1 : 1; + + g_variant_iter_init (&iter, value1); + while (g_variant_iter_next (&iter, "{&sv}", &key, &val1)) { + if (!g_variant_lookup (value2, key, "v", &val2)) { + g_variant_unref (val1); + return -1; + } + if (!g_variant_equal (val1, val2)) { + g_variant_unref (val1); + g_variant_unref (val2); + return -1; + } + g_variant_unref (val1); + g_variant_unref (val2); + } + + return 0; +} + static gint _nm_property_compare_strdict (GVariant *value1, GVariant *value2) { @@ -106,6 +138,8 @@ nm_property_compare (GVariant *value1, GVariant *value2) ret = g_variant_compare (value1, value2); else if (g_variant_is_of_type (value1, G_VARIANT_TYPE ("a{ss}"))) ret = _nm_property_compare_strdict (value1, value2); + else if (g_variant_is_of_type (value1, G_VARIANT_TYPE ("a{sv}"))) + ret = _nm_property_compare_vardict (value1, value2); else if (g_variant_type_is_array (type1)) ret = _nm_property_compare_collection (value1, value2); else if (g_variant_type_is_tuple (type1)) diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h index 6b8d58726a..31196694ca 100644 --- a/libnm-core/nm-utils-private.h +++ b/libnm-core/nm-utils-private.h @@ -78,6 +78,8 @@ void _nm_utils_bytes_from_dbus (GVariant *dbus_value, char * _nm_utils_hwaddr_canonical_or_invalid (const char *mac, gssize length); +GPtrArray * _nm_utils_team_link_watchers_from_variant (GVariant *value); +GVariant * _nm_utils_team_link_watchers_to_variant (GPtrArray *link_watchers); /* JSON to GValue conversion macros */ diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index b150521c2e..3ce378b653 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4815,6 +4815,202 @@ _nm_utils_team_config_set (char **conf, } #endif +/** + * _nm_utils_team_link_watchers_to_variant: + * @link_watchers: (element-type NMTeamLinkWatcher): array of #NMTeamLinkWatcher + * + * Utility function to convert a #GPtrArray of #NMTeamLinkWatcher objects + * representing link watcher configuration for team devices into a #GVariant + * of type 'aa{sv}' representing an array of link watchers. + * + * Returns: (transfer none): a new floating #GVariant representing link watchers. + **/ +GVariant * +_nm_utils_team_link_watchers_to_variant (GPtrArray *link_watchers) +{ + GVariantBuilder builder; + int i; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); + + if (!link_watchers) + goto end; + + for (i = 0; i < link_watchers->len; i++) { + NMTeamLinkWatcher *watcher = link_watchers->pdata[i]; + GVariantBuilder watcher_builder; + const char *name; + int int_val; + NMTeamLinkWatcherArpPingFlags flags; + + g_variant_builder_init (&watcher_builder, G_VARIANT_TYPE ("a{sv}")); + + name = nm_team_link_watcher_get_name (watcher); + g_variant_builder_add (&watcher_builder, "{sv}", + "name", + g_variant_new_string (name)); + + if nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL) { + int_val = nm_team_link_watcher_get_delay_up (watcher); + if (int_val) { + g_variant_builder_add (&watcher_builder, "{sv}", + "delay-up", + g_variant_new_int32 (int_val)); + } + int_val = nm_team_link_watcher_get_delay_down (watcher); + if (int_val) { + g_variant_builder_add (&watcher_builder, "{sv}", + "delay-down", + g_variant_new_int32 (int_val)); + } + g_variant_builder_add (&builder, "a{sv}", &watcher_builder); + continue; + } + + /* Common properties for arp_ping and nsna_ping link watchers */ + int_val = nm_team_link_watcher_get_init_wait (watcher); + if (int_val) { + g_variant_builder_add (&watcher_builder, "{sv}", + "init-wait", + g_variant_new_int32 (int_val)); + } + int_val = nm_team_link_watcher_get_interval (watcher); + if (int_val) { + g_variant_builder_add (&watcher_builder, "{sv}", + "interval", + g_variant_new_int32 (int_val)); + } + int_val = nm_team_link_watcher_get_missed_max (watcher); + if (int_val != 3) { + g_variant_builder_add (&watcher_builder, "{sv}", + "missed-max", + g_variant_new_int32 (int_val)); + } + g_variant_builder_add (&watcher_builder, "{sv}", + "target-host", + g_variant_new_string (nm_team_link_watcher_get_target_host (watcher))); + + if nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING) { + g_variant_builder_add (&builder, "a{sv}", &watcher_builder); + continue; + } + + /* arp_ping watcher only */ + g_variant_builder_add (&watcher_builder, "{sv}", + "source-host", + g_variant_new_string (nm_team_link_watcher_get_source_host (watcher))); + flags = nm_team_link_watcher_get_flags (watcher); + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE) { + g_variant_builder_add (&watcher_builder, "{sv}", + "validate-active", + g_variant_new_boolean (TRUE)); + } + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE) { + g_variant_builder_add (&watcher_builder, "{sv}", + "validate-inactive", + g_variant_new_boolean (TRUE)); + } + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS) { + g_variant_builder_add (&watcher_builder, "{sv}", + "send-always", + g_variant_new_boolean (TRUE)); + } + g_variant_builder_add (&builder, "a{sv}", &watcher_builder); + } +end: + return g_variant_builder_end (&builder); +} + +/** + * _nm_utils_team_link_watchers_from_variant: + * @value: a #GVariant of type 'aa{sv}' + * + * Utility function to convert a #GVariant representing a list of team link + * watchers int a #GPtrArray of #NMTeamLinkWatcher objects. + * + * Returns: (transfer full) (element-type NMTeamLinkWatcher): a newly allocated + * #GPtrArray of #NMTeamLinkWatcher objects. + **/ +GPtrArray * +_nm_utils_team_link_watchers_from_variant (GVariant *value) +{ + GPtrArray *link_watchers; + GVariantIter iter; + GVariant *watcher_var; + + g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL); + + link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); + g_variant_iter_init (&iter, value); + + while (g_variant_iter_next (&iter, "@a{sv}", &watcher_var)) { + NMTeamLinkWatcher *watcher; + const char *name; + int val1, val2, val3 = 0; + const char *target_host = NULL, *source_host = NULL; + gboolean bval; + NMTeamLinkWatcherArpPingFlags flags = NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE; + GError *error = NULL; + + if (!g_variant_lookup (watcher_var, "name", "&s", &name)) + goto next; + if (!NM_IN_STRSET (name, + NM_TEAM_LINK_WATCHER_ETHTOOL, + NM_TEAM_LINK_WATCHER_ARP_PING, + NM_TEAM_LINK_WATCHER_NSNA_PING)) { + goto next; + } + + if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) { + if (!g_variant_lookup (watcher_var, "delay-up", "i", &val1)) + val1 = 0; + if (!g_variant_lookup (watcher_var, "delay-down", "i", &val2)) + val2 = 0; + watcher = nm_team_link_watcher_new_ethtool (val1, val2, &error); + } else { + if (!g_variant_lookup (watcher_var, "target-host", "&s", &target_host)) + goto next; + if (!g_variant_lookup (watcher_var, "init_wait", "i", &val1)) + val1 = 0; + if (!g_variant_lookup (watcher_var, "interval", "i", &val2)) + val2 = 0; + if (!g_variant_lookup (watcher_var, "missed-max", "i", &val3)) + val3 = 3; + if nm_streq (name, NM_TEAM_LINK_WATCHER_ARP_PING) { + if (!g_variant_lookup (watcher_var, "source-host", "&s", &source_host)) + goto next; + if (!g_variant_lookup (watcher_var, "validate-active", "b", &bval)) + bval = FALSE; + if (bval) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE; + if (!g_variant_lookup (watcher_var, "validate-inactive", "b", &bval)) + bval = FALSE; + if (bval) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE; + if (!g_variant_lookup (watcher_var, "send-always", "b", &bval)) + bval = FALSE; + if (bval) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS; + watcher = nm_team_link_watcher_new_arp_ping (val1, val2, val3, + target_host, source_host, + flags, &error); + } else + watcher = nm_team_link_watcher_new_nsna_ping (val1, val2, val3, + target_host, &error); + } + if (!watcher) { + g_clear_error (&error); + goto next; + } + + g_ptr_array_add (link_watchers, watcher); +next: + g_variant_unref (watcher_var); + } + + return link_watchers; +} + static char * attribute_escape (const char *src, char c1, char c2) { diff --git a/libnm/generate-setting-docs.py b/libnm/generate-setting-docs.py index aa0c96ebb2..50ae9d4682 100755 --- a/libnm/generate-setting-docs.py +++ b/libnm/generate-setting-docs.py @@ -54,6 +54,7 @@ dbus_type_name_map = { 'ay': 'byte array', 'a{ss}': 'dict of string to string', 'a{sv}': 'vardict', + 'aa{sv}': 'array of vardict', 'aau': 'array of array of uint32', 'aay': 'array of byte array', 'a(ayuay)': 'array of legacy IPv6 address struct', From 466f8e0dd55d665a77ae34ac1f784214dd877d11 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Mon, 6 Nov 2017 15:47:32 +0100 Subject: [PATCH 05/23] libnm-core: team: expose the new link-watchers property It will allow explicit configuration of link-watchers in the team configuration. (cherry picked from commit ca816ae10e5b7b12608aa50d70c8dded0d6218df) --- clients/common/settings-docs.c.in | 1 + libnm-core/nm-setting-team.c | 258 ++++++++++++++++++++++++++++++ libnm-core/nm-setting-team.h | 15 ++ libnm/libnm.ver | 6 + 4 files changed, 280 insertions(+) diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index 3d6f012bf7..160fcfc720 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -316,6 +316,7 @@ #define DESCRIBE_DOC_NM_SETTING_SERIAL_SEND_DELAY N_("Time to delay between each byte sent to the modem, in microseconds.") #define DESCRIBE_DOC_NM_SETTING_SERIAL_STOPBITS N_("Number of stop bits for communication on the serial port. Either 1 or 2. The 1 in \"8n1\" for example.") #define DESCRIBE_DOC_NM_SETTING_TEAM_CONFIG N_("The JSON configuration for the team network interface. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details.") +#define DESCRIBE_DOC_NM_SETTING_TEAM_LINK_WATCHERS N_("Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-incative', 'send-always'. See teamd.conf man for more details.") #define DESCRIBE_DOC_NM_SETTING_TEAM_MCAST_REJOIN_COUNT N_("Corresponds to the teamd mcast_rejoin.count.") #define DESCRIBE_DOC_NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL N_("Corresponds to the teamd mcast_rejoin.interval.") #define DESCRIBE_DOC_NM_SETTING_TEAM_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c index b14094a026..37c9094c92 100644 --- a/libnm-core/nm-setting-team.c +++ b/libnm-core/nm-setting-team.c @@ -585,6 +585,7 @@ typedef struct { gint runner_sys_prio; gint runner_min_ports; char *runner_agg_select_policy; + GPtrArray *link_watchers; /* Array of NMTeamLinkWatcher */ } NMSettingTeamPrivate; /* Keep aligned with _prop_to_keys[] */ @@ -605,6 +606,7 @@ enum { PROP_RUNNER_SYS_PRIO, PROP_RUNNER_MIN_PORTS, PROP_RUNNER_AGG_SELECT_POLICY, + PROP_LINK_WATCHERS, LAST_PROP }; @@ -630,6 +632,7 @@ static const _NMUtilsTeamPropertyKeys _prop_to_keys[LAST_PROP] = { [PROP_RUNNER_MIN_PORTS] = { "runner", "min_ports", NULL, 0 }, [PROP_RUNNER_AGG_SELECT_POLICY] = { "runner", "agg_select_policy", NULL, {.default_str = NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT} }, + [PROP_LINK_WATCHERS] = { "link_watch", NULL, NULL, 0 } }; /** @@ -992,10 +995,163 @@ nm_setting_team_add_runner_tx_hash (NMSettingTeam *setting, const char *txhash) return TRUE; } +/** + * nm_setting_team_get_num_link_watchers: + * @setting: the #NMSettingTeam + * + * Returns: the number of configured link watchers + * + * Since: 1.10.2 + **/ +guint +nm_setting_team_get_num_link_watchers (NMSettingTeam *setting) +{ + NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); + + g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), 0); + + return priv->link_watchers->len; +} + +/** + * nm_setting_team_get_link_watcher: + * @setting: the #NMSettingTeam + * @idx: index number of the link watcher to return + * + * Returns: (transfer none): the link watcher at index @idx. + * + * Since: 1.10.2 + **/ +NMTeamLinkWatcher * +nm_setting_team_get_link_watcher (NMSettingTeam *setting, guint idx) +{ + NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); + + g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), NULL); + g_return_val_if_fail (idx < priv->link_watchers->len, NULL); + + return priv->link_watchers->pdata[idx]; +} + +/** + * nm_setting_team_add_link_watcher: + * @setting: the #NMSettingTeam + * @link_watcher: the link watcher to add + * + * Appends a new link watcher to the setting. + * + * Returns: %TRUE if the link watcher is added; %FALSE if an identical link + * watcher was already there. + * + * Since: 1.10.2 + **/ +gboolean +nm_setting_team_add_link_watcher (NMSettingTeam *setting, + NMTeamLinkWatcher *link_watcher) +{ + NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); + guint i; + + g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), FALSE); + g_return_val_if_fail (link_watcher != NULL, FALSE); + + for (i = 0; i < priv->link_watchers->len; i++) { + if (nm_team_link_watcher_equal (priv->link_watchers->pdata[i], link_watcher)) + return FALSE; + } + + g_ptr_array_add (priv->link_watchers, nm_team_link_watcher_dup (link_watcher)); + g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_LINK_WATCHERS); + return TRUE; +} + +/** + * nm_setting_team_remove_link_watcher: + * @setting: the #NMSettingTeam + * @idx: index number of the link watcher to remove + * + * Removes the link watcher at index #idx. + * + * Since: 1.10.2 + **/ +void +nm_setting_team_remove_link_watcher (NMSettingTeam *setting, guint idx) +{ + NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); + + g_return_if_fail (NM_IS_SETTING_TEAM (setting)); + g_return_if_fail (idx < priv->link_watchers->len); + + g_ptr_array_remove_index (priv->link_watchers, idx); + g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_LINK_WATCHERS); +} + +/** + * nm_setting_team_remove_link_watcher_by_value: + * @setting: the #NMSettingTeam + * @link_watcher: the link watcher to remove + * + * Removes the link watcher entry matching link_watcher. + * + * Returns: %TRUE if the link watcher was found and removed, %FALSE otherwise. + * + * Since: 1.10.2 + **/ +gboolean +nm_setting_team_remove_link_watcher_by_value (NMSettingTeam *setting, + NMTeamLinkWatcher *link_watcher) +{ + NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); + guint i; + + g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), FALSE); + + for (i = 0; i < priv->link_watchers->len; i++) { + if (nm_team_link_watcher_equal (priv->link_watchers->pdata[i], link_watcher)) { + g_ptr_array_remove_index (priv->link_watchers, i); + g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_LINK_WATCHERS); + return TRUE; + } + } + return FALSE; +} + +/** + * nm_setting_team_clear_link_watchers: + * @setting: the #NMSettingTeam + * + * Removes all configured link watchers. + * + * Since: 1.10.2 + **/ +void +nm_setting_team_clear_link_watchers (NMSettingTeam *setting) { + NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); + + g_return_if_fail (NM_IS_SETTING_TEAM (setting)); + + g_ptr_array_set_size (priv->link_watchers, 0); + g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_LINK_WATCHERS); +} + +static GVariant * +team_link_watchers_to_dbus (const GValue *prop_value) +{ + return _nm_utils_team_link_watchers_to_variant (g_value_get_boxed (prop_value)); +} + +static void +team_link_watchers_from_dbus (GVariant *dbus_value, + GValue *prop_value) +{ + g_value_take_boxed (prop_value, _nm_utils_team_link_watchers_from_variant (dbus_value)); +} + static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); + guint i; if (!_nm_connection_verify_required_interface_name (connection, error)) return FALSE; @@ -1034,6 +1190,48 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + /* Validate link watchers */ + for (i = 0; i < priv->link_watchers->len; i++) { + NMTeamLinkWatcher *link_watcher = priv->link_watchers->pdata[i]; + const char *name = nm_team_link_watcher_get_name (link_watcher); + + if (!name) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING, + _("missing link watcher name")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), + NM_SETTING_TEAM_LINK_WATCHERS); + return FALSE; + } + if (!NM_IN_STRSET (name, + NM_TEAM_LINK_WATCHER_ETHTOOL, + NM_TEAM_LINK_WATCHER_ARP_PING, + NM_TEAM_LINK_WATCHER_NSNA_PING)) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING, + _("unknown link watcher \"%s\""), name); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), + NM_SETTING_TEAM_LINK_WATCHERS); + return FALSE; + } + + if (NM_IN_STRSET (name, + NM_TEAM_LINK_WATCHER_ARP_PING, + NM_TEAM_LINK_WATCHER_NSNA_PING) + && !nm_team_link_watcher_get_target_host (link_watcher)) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING, + _("missing target host")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), + NM_SETTING_TEAM_LINK_WATCHERS); + return FALSE; + } + if (nm_streq (name, NM_TEAM_LINK_WATCHER_ARP_PING) + && !nm_team_link_watcher_get_source_host (link_watcher)) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING, + _("missing source address")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), + NM_SETTING_TEAM_LINK_WATCHERS); + return FALSE; + } + } /* NOTE: normalizable/normalizable-errors must appear at the end with decreasing severity. * Take care to properly order statements with priv->config above. */ @@ -1046,7 +1244,9 @@ compare_property (NMSetting *setting, const GParamSpec *prop_spec, NMSettingCompareFlags flags) { + NMSettingTeamPrivate *a_priv, *b_priv; NMSettingClass *parent_class; + guint i, j; /* If we are trying to match a connection in order to assume it (and thus * @flags contains INFERRABLE), use the "relaxed" matching for team @@ -1059,6 +1259,24 @@ compare_property (NMSetting *setting, NM_SETTING_TEAM_GET_PRIVATE (other)->config, FALSE); } + if (nm_streq0 (prop_spec->name, NM_SETTING_TEAM_LINK_WATCHERS)) { + a_priv = NM_SETTING_TEAM_GET_PRIVATE (setting); + b_priv = NM_SETTING_TEAM_GET_PRIVATE (other); + + if (a_priv->link_watchers->len != b_priv->link_watchers->len) + return FALSE; + for (i = 0; i < a_priv->link_watchers->len; i++) { + for (j = 0; j < b_priv->link_watchers->len; j++) { + if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i], + b_priv->link_watchers->pdata[j])) { + break; + } + if (j == b_priv->link_watchers->len) + return FALSE; + } + } + return TRUE; + } /* Otherwise chain up to parent to handle generic compare */ parent_class = NM_SETTING_CLASS (nm_setting_team_parent_class); @@ -1073,6 +1291,7 @@ nm_setting_team_init (NMSettingTeam *setting) priv->runner = g_strdup (NM_SETTING_TEAM_RUNNER_ROUNDROBIN); priv->runner_sys_prio = NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT; priv->runner_tx_balancer_interval = NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT; + priv->link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); } static void @@ -1087,6 +1306,7 @@ finalize (GObject *object) g_free (priv->runner_agg_select_policy); if (priv->runner_tx_hash) g_ptr_array_unref (priv->runner_tx_hash); + g_ptr_array_unref (priv->link_watchers); G_OBJECT_CLASS (nm_setting_team_parent_class)->finalize (object); } @@ -1268,6 +1488,12 @@ set_property (GObject *object, guint prop_id, align_value = value; align_config = TRUE; break; + case PROP_LINK_WATCHERS: + g_ptr_array_unref (priv->link_watchers); + priv->link_watchers = _nm_utils_copy_array (g_value_get_boxed (value), + (NMUtilsCopyFunc) nm_team_link_watcher_dup, + (GDestroyNotify) nm_team_link_watcher_unref); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1331,6 +1557,11 @@ get_property (GObject *object, guint prop_id, case PROP_RUNNER_AGG_SELECT_POLICY: g_value_set_string (value, nm_setting_team_get_runner_agg_select_policy (setting)); break; + case PROP_LINK_WATCHERS: + g_value_take_boxed (value, _nm_utils_copy_array (priv->link_watchers, + (NMUtilsCopyFunc) nm_team_link_watcher_dup, + (GDestroyNotify) nm_team_link_watcher_unref)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1574,6 +1805,33 @@ nm_setting_team_class_init (NMSettingTeamClass *setting_class) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * NMSettingTeam:link-watchers: + * + * Link watchers configuration for the connection: each link watcher is + * defined by a dictionary, whose keys depend upon the selected link + * watcher. Available link watchers are 'ethtool', 'nsna_ping' and + * 'arp_ping' and it is specified in the dictionary with the key 'name'. + * Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; + * nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; + * arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', + * 'validate-incative', 'send-always'. See teamd.conf man for more details. + * + * Element-Type: NMTeamLinkWatcher + * Since: 1.10.2 + **/ + g_object_class_install_property + (object_class, PROP_LINK_WATCHERS, + g_param_spec_boxed (NM_SETTING_TEAM_LINK_WATCHERS, "", "", + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + _nm_setting_class_transform_property (parent_class, + NM_SETTING_TEAM_LINK_WATCHERS, + G_VARIANT_TYPE ("aa{sv}"), + team_link_watchers_to_dbus, + team_link_watchers_from_dbus); + /* ---dbus--- * property: interface-name * format: string diff --git a/libnm-core/nm-setting-team.h b/libnm-core/nm-setting-team.h index aaaaee2c63..fe30c5a3a4 100644 --- a/libnm-core/nm-setting-team.h +++ b/libnm-core/nm-setting-team.h @@ -127,6 +127,7 @@ NMTeamLinkWatcherArpPingFlags nm_team_link_watcher_get_flags (NMTeamLinkWatcher #define NM_SETTING_TEAM_RUNNER_SYS_PRIO "runner-sys-prio" #define NM_SETTING_TEAM_RUNNER_MIN_PORTS "runner-min-ports" #define NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY "runner-agg-select-policy" +#define NM_SETTING_TEAM_LINK_WATCHERS "link-watchers" #define NM_SETTING_TEAM_RUNNER_BROADCAST "broadcast" #define NM_SETTING_TEAM_RUNNER_ROUNDROBIN "roundrobin" @@ -210,6 +211,20 @@ NM_AVAILABLE_IN_1_10_2 void nm_setting_team_remove_runner_tx_hash (NMSettingTeam *setting, int idx); NM_AVAILABLE_IN_1_10_2 gboolean nm_setting_team_add_runner_tx_hash (NMSettingTeam *setting, const char *txhash); +NM_AVAILABLE_IN_1_10_2 +guint nm_setting_team_get_num_link_watchers (NMSettingTeam *setting); +NM_AVAILABLE_IN_1_10_2 +NMTeamLinkWatcher * nm_setting_team_get_link_watcher (NMSettingTeam *setting, guint idx); +NM_AVAILABLE_IN_1_10_2 +gboolean nm_setting_team_add_link_watcher (NMSettingTeam *setting, + NMTeamLinkWatcher *link_watcher); +NM_AVAILABLE_IN_1_10_2 +void nm_setting_team_remove_link_watcher (NMSettingTeam *setting, guint idx); +NM_AVAILABLE_IN_1_10_2 +gboolean nm_setting_team_remove_link_watcher_by_value (NMSettingTeam *setting, + NMTeamLinkWatcher *link_watcher); +NM_AVAILABLE_IN_1_10_2 +void nm_setting_team_clear_link_watchers (NMSettingTeam *setting); G_END_DECLS #endif /* __NM_SETTING_TEAM_H__ */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 63fa05df27..b8f071067c 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1226,11 +1226,15 @@ libnm_1_10_2 { global: nm_remote_connection_update2; nm_remote_connection_update2_finish; + nm_setting_team_add_link_watcher; nm_setting_team_add_runner_tx_hash; + nm_setting_team_clear_link_watchers; + nm_setting_team_get_link_watcher; nm_setting_team_get_mcast_rejoin_count; nm_setting_team_get_mcast_rejoin_interval; nm_setting_team_get_notify_peers_count; nm_setting_team_get_notify_peers_interval; + nm_setting_team_get_num_link_watchers; nm_setting_team_get_num_runner_tx_hash; nm_setting_team_get_runner; nm_setting_team_get_runner_hwaddr_policy; @@ -1247,6 +1251,8 @@ global: nm_setting_team_port_get_sticky; nm_setting_team_port_get_lacp_prio; nm_setting_team_port_get_lacp_key; + nm_setting_team_remove_link_watcher; + nm_setting_team_remove_link_watcher_by_value; nm_setting_team_remove_runner_tx_hash; nm_setting_team_remove_runner_tx_hash_by_value; nm_settings_update2_flags_get_type; From 2eacf89f3834cd36107f488fc8faffef3039c2b7 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Fri, 10 Nov 2017 01:25:23 +0100 Subject: [PATCH 06/23] cli: add support to Team link watchers (cherry picked from commit 4657390d458df34bdf85ed3903d0566d11ce61dd) --- clients/common/nm-meta-setting-desc.c | 242 ++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 9467719811..2febf9f2a2 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -241,6 +241,150 @@ _parse_ip_route (int family, return route; } +static char * +_dump_team_link_watcher (NMTeamLinkWatcher *watcher) +{ + const char *name; + NMTeamLinkWatcherArpPingFlags flags; + GString *w_dump; + + if (!watcher) + return NULL; + + w_dump = g_string_new (NULL); + name = nm_team_link_watcher_get_name (watcher); + g_string_append_printf (w_dump, "name=%s", name); + +#define DUMP_WATCHER_INT(str, watcher, name, key) \ + G_STMT_START { \ + int _val = nm_team_link_watcher_get_##key (watcher); \ + \ + if (_val) \ + g_string_append_printf (str, " %s=%d", name, _val); \ + } G_STMT_END; + + if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) { + DUMP_WATCHER_INT (w_dump, watcher, "delay-up", delay_up); + DUMP_WATCHER_INT (w_dump, watcher, "delay-down", delay_down); + return g_string_free (w_dump, FALSE); + } + /* NM_TEAM_LINK_WATCHER_NSNA_PING and NM_TEAM_LINK_WATCHER_ARP_PING */ + DUMP_WATCHER_INT (w_dump, watcher, "init-wait", init_wait); + DUMP_WATCHER_INT (w_dump, watcher, "initerval", interval); + DUMP_WATCHER_INT (w_dump, watcher, "missed-max", missed_max); +#undef DUMP_WATCHER_INT + g_string_append_printf (w_dump, " target-host=%s", + nm_team_link_watcher_get_target_host (watcher)); + + if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING)) + return g_string_free (w_dump, FALSE); + + g_string_append_printf (w_dump, " source-host=%s", + nm_team_link_watcher_get_source_host (watcher)); + flags = nm_team_link_watcher_get_flags (watcher); + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE) + g_string_append_printf (w_dump, " validate-active=true"); + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE) + g_string_append_printf (w_dump, " validate-inactive=true"); + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS) + g_string_append_printf (w_dump, "send-always=true"); + + return g_string_free (w_dump, FALSE); +} + +static NMTeamLinkWatcher * +_parse_team_link_watcher (const char *str, + GError **error) +{ + gs_strfreev char **watcherv = NULL; + gs_free char *str_clean = NULL; + guint i; + gs_free const char *name = NULL; + int val1 = 0, val2 = 0, val3 = 3; + gs_free const char *target_host = NULL; + gs_free const char *source_host = NULL; + NMTeamLinkWatcherArpPingFlags flags = 0; + + nm_assert (str); + nm_assert (!error || !*error); + + str_clean = g_strstrip (g_strdup (str)); + watcherv = nmc_strsplit_set (str_clean, " \t", 0); + if (!watcherv || !watcherv[0]) { + g_set_error (error, 1, 0, "'%s' is not valid", str); + return NULL; + } + + for (i = 0; watcherv[i]; i++) { + gs_strfreev char **pair = NULL; + + pair = nmc_strsplit_set (watcherv[i], "=", 0); + if (!pair[0]) { + g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i], + "properties should be specified as 'key=value'"); + return NULL; + } + if (!pair[1]) { + g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i], + "missing key value"); + return NULL; + } + if (pair[2]) { + g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i], + "properties should be specified as 'key=value'"); + return NULL; + } + + if (nm_streq (pair[0], "name")) + name = g_strdup (pair[1]); + else if ( nm_streq (pair[0], "delay-up") + || nm_streq (pair[0], "init-wait")) + val1 = _nm_utils_ascii_str_to_int64 (pair[1], 10, 0, G_MAXINT32, -1); + else if ( nm_streq (pair[0], "delay-down") + || nm_streq (pair[0], "interval")) + val2 = _nm_utils_ascii_str_to_int64 (pair[1], 10, 0, G_MAXINT32, -1); + else if (nm_streq (pair[0], "missed-max")) + val3 = _nm_utils_ascii_str_to_int64 (pair[1], 10, 0, G_MAXINT32, -1); + else if (nm_streq (pair[0], "target-host")) + target_host = g_strdup (pair[1]); + else if (nm_streq (pair[0], "source-host")) + source_host = g_strdup (pair[1]); + else if (nm_streq (pair[0], "validate-active")) { + if (nm_streq (pair[1], "true")) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE; + } else if (nm_streq (pair[0], "validate-inactive")) { + if (nm_streq (pair[1], "true")) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE; + } else if (nm_streq (pair[0], "send-always")) { + if (nm_streq (pair[1], "true")) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS; + } else { + g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i], + "unknown key"); + return NULL; + } + + if ((val1 < 0) || (val2 < 0) || (val3 < 0)) { + g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i], + "value is not a valid number [0, MAXINT]"); + return NULL; + } + } + + if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) + return nm_team_link_watcher_new_ethtool (val1, val2, error); + else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_NSNA_PING)) + return nm_team_link_watcher_new_nsna_ping (val1, val2, val3, target_host, error); + else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ARP_PING)) + return nm_team_link_watcher_new_arp_ping (val1, val2, val3, target_host, source_host, flags, error); + + if (!name) + g_set_error (error, 1, 0, "link watcher name missing"); + else + g_set_error (error, 1, 0, "unknown link watcher name: '%s'", name); + return NULL; +} + /* Max priority values from libnm-core/nm-setting-vlan.c */ #define MAX_SKB_PRIO G_MAXUINT32 #define MAX_8021P_PRIO 7 /* Max 802.1p priority */ @@ -3707,6 +3851,78 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_team_runner_tx_hash, nm_setting_team_remove_runner_tx_hash, _validate_and_remove_team_runner_tx_hash) +static gconstpointer +_get_fcn_team_link_watchers (ARGS_GET_FCN) +{ + NMSettingTeam *s_team = NM_SETTING_TEAM (setting); + GString *printable; + guint32 num_watchers, i; + NMTeamLinkWatcher *watcher; + char *watcher_str; + + RETURN_UNSUPPORTED_GET_TYPE (); + + printable = g_string_new (NULL); + + num_watchers = nm_setting_team_get_num_link_watchers (s_team); + for (i = 0; i < num_watchers; i++) { + watcher = nm_setting_team_get_link_watcher (s_team, i); + watcher_str = _dump_team_link_watcher (watcher); + if (watcher_str) { + if (printable->len > 0) + g_string_append (printable, ", "); + g_string_append (printable, watcher_str); + g_free (watcher_str); + } + } + + RETURN_STR_TO_FREE (g_string_free (printable, FALSE)); +} + +static gboolean +_set_fcn_team_link_watchers (ARGS_SET_FCN) +{ + gs_strfreev char **strv = NULL; + const char *const*iter; + NMTeamLinkWatcher *watcher; + + strv = nmc_strsplit_set (value, ",", 0); + for (iter = (const char *const*) strv; *iter; iter++) { + watcher = _parse_team_link_watcher (*iter, error); + if (!watcher) + return FALSE; + nm_setting_team_add_link_watcher (NM_SETTING_TEAM (setting), watcher); + nm_team_link_watcher_unref (watcher); + } + return TRUE; +} + +static gboolean +_validate_and_remove_team_link_watcher (NMSettingTeam *setting, + const char *watcher_str, + GError **error) +{ + NMTeamLinkWatcher *watcher; + gboolean ret; + + watcher = _parse_team_link_watcher (watcher_str, error); + if (!watcher) + return FALSE; + + ret = nm_setting_team_remove_link_watcher_by_value (setting, watcher); + if (!ret) { + g_set_error (error, 1, 0, _("the property doesn't contain link watcher '%s'"), + watcher_str); + } + nm_team_link_watcher_unref (watcher); + return ret; +} +DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_team_link_watchers, + NM_SETTING_TEAM, + nm_setting_team_get_num_link_watchers, + nm_setting_team_remove_link_watcher, + _validate_and_remove_team_link_watcher) + static gconstpointer _get_fcn_vlan_flags (ARGS_GET_FCN) { @@ -4505,6 +4721,24 @@ static const NMMetaPropertyType _pt_gobject_devices = { "{ \"device\": \"team0\", \"runner\": {\"name\": \"roundrobin\"}, \"ports\": {\"eth1\": {}, \"eth2\": {}} }\n" \ " set team.config /etc/my-team.conf\n") +#define TEAM_LINK_WATCHERS_DESCRIBE_MESSAGE \ + N_("Enter a list of link watchers formatted as dictionaries where the keys " \ + "are teamd properties. Dictionary pairs are in the form: key=value and pairs " \ + "are separated by ' '. Dictionaries are separated with ','.\n" \ + "The keys allowed/required in the dictionary change on the basis of the link " \ + "watcher type, while the only property common to all the link watchers is " \ + " 'name'*, which defines the link watcher to be specified.\n\n" \ + "Properties available for the 'ethtool' link watcher:\n" \ + " 'delay-up', 'delay-down'\n\n" \ + "Properties available for the 'nsna_ping' link watcher:\n" \ + " 'init-wait', 'interval', 'missed-max', 'target-host'*\n\n" \ + "Properties available for the 'arp_ping' include all the ones for 'nsna_ping' and:\n" \ + " 'source-host', 'validate-active', 'validate-inactive', 'send-always'.\n\n" \ + "Properties flagged with a '*' are mandatory.\n\n" \ + "Example:\n" \ + " name=arp_ping,source-host=172.16.1.1,target-host=172.16.1.254; name=ethtool,delay-up=3\n") + + #define DEFINE_DCB_PROPRITY_PROPERTY_TYPE \ .property_type = &_pt_gobject_int, \ .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, \ @@ -6189,6 +6423,14 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_PORT_CONFIG), ), ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_TEAM_LINK_WATCHERS, + .describe_message = TEAM_LINK_WATCHERS_DESCRIBE_MESSAGE, + .property_type = DEFINE_PROPERTY_TYPE ( + .get_fcn = _get_fcn_team_link_watchers, + .set_fcn = _set_fcn_team_link_watchers, + .remove_fcn = _remove_fcn_team_link_watchers, + ), + ), NULL }; From a1c25edfe867d89a7f032f7dfec299050ee556ea Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Fri, 10 Nov 2017 19:25:13 +0100 Subject: [PATCH 07/23] libnm-core: synchronize team.config when team.link_watchers is set. (cherry picked from commit e59878ce1911f3930c60a104673b59fb3c5ae001) --- libnm-core/nm-setting-team.c | 3 + libnm-core/nm-utils.c | 117 +++++++++++++++++++++++++++++++++-- 2 files changed, 115 insertions(+), 5 deletions(-) diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c index 37c9094c92..d2a343803c 100644 --- a/libnm-core/nm-setting-team.c +++ b/libnm-core/nm-setting-team.c @@ -1493,6 +1493,9 @@ set_property (GObject *object, guint prop_id, priv->link_watchers = _nm_utils_copy_array (g_value_get_boxed (value), (NMUtilsCopyFunc) nm_team_link_watcher_dup, (GDestroyNotify) nm_team_link_watcher_unref); + if (priv->link_watchers->len) + align_value = value; + align_config = TRUE; break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 3ce378b653..24c7a8ed6f 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4622,6 +4622,72 @@ _nm_utils_team_config_get (const char *conf, return value; } +static json_t * +_nm_utils_team_link_watcher_to_json (NMTeamLinkWatcher *watcher) +{ + const char *name; + int int_val; + const char *str_val; + NMTeamLinkWatcherArpPingFlags flags = 0; + json_t *json_element; + + g_return_val_if_fail (watcher, NULL); + + json_element = json_object (); + name = nm_team_link_watcher_get_name (watcher); + if (!name) + goto fail; + + json_object_set_new (json_element, "name", json_string (name)); + + if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) { + int_val = nm_team_link_watcher_get_delay_up (watcher); + if (int_val) + json_object_set_new (json_element, "delay_up", json_integer (int_val)); + int_val = nm_team_link_watcher_get_delay_down (watcher); + if (int_val) + json_object_set_new (json_element, "delay_down", json_integer (int_val)); + return json_element; + } + + int_val = nm_team_link_watcher_get_init_wait (watcher); + if (int_val) + json_object_set_new (json_element, "init_wait", json_integer (int_val)); + int_val = nm_team_link_watcher_get_interval (watcher); + if (int_val) + json_object_set_new (json_element, "interval", json_integer (int_val)); + int_val = nm_team_link_watcher_get_missed_max (watcher); + if (int_val != 3) + json_object_set_new (json_element, "missed_max", json_integer (int_val)); + str_val = nm_team_link_watcher_get_target_host (watcher); + if (!str_val) + goto fail; + json_object_set_new (json_element, "target_host", json_string (str_val)); + + if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING)) + return json_element; + + str_val = nm_team_link_watcher_get_source_host (watcher); + if (!str_val) + goto fail; + json_object_set_new (json_element, "source_host", json_string (str_val)); + + flags = nm_team_link_watcher_get_flags (watcher); + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE) + json_object_set_new (json_element, "validate_active", json_string ("true")); + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE) + json_object_set_new (json_element, "validate_inactive", json_string ("true")); + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS) + json_object_set_new (json_element, "send_always", json_string ("true")); + + return json_element; + +fail: + json_decref (json_element); + return NULL; +} + + /* if conf is updated in place returns TRUE */ gboolean _nm_utils_team_config_set (char **conf, @@ -4634,8 +4700,12 @@ _nm_utils_team_config_set (char **conf, json_error_t jerror; gboolean updated = FALSE; char **strv; + GPtrArray *array; const char *iter_key = key; int i; + NMTeamLinkWatcher *watcher; + + g_return_val_if_fail (key, FALSE); json = json_loads (*conf?: "{}", JSON_REJECT_DUPLICATES, &jerror); if (!json) @@ -4687,14 +4757,51 @@ _nm_utils_team_config_set (char **conf, else if (G_VALUE_HOLDS_BOOLEAN (value)) json_value = json_boolean (g_value_get_boolean (value)); else if (G_VALUE_HOLDS_BOXED (value)) { - strv = g_value_get_boxed (value); - if (strv) { + if (nm_streq (key, "link_watch")) { + array = g_value_get_boxed (value); + if (!array || !array->len) { + updated = FALSE; + goto done; + } + + /* + * json_value: will hold the final link_watcher json (array) object + * json_element: is the next link_watcher to append to json_value + * json_link: used to transit the json_value from a single link_watcher + * object to an array of link watcher objects + */ + json_value = NULL; + for (i = 0; i < array->len; i++) { + watcher = array->pdata[i]; + json_element = _nm_utils_team_link_watcher_to_json (watcher); + if (!json_element) + continue; + if (!json_value) { + json_value = json_element; + continue; + } + if (!json_is_array (json_value)) { + json_link = json_value; + json_value = json_array (); + json_array_append_new (json_value, json_link); + } + json_array_append_new (json_value, json_element); + } + } else if ( nm_streq (key, "runner") + && nm_streq0 (key2, "tx_hash")) { + strv = g_value_get_boxed (value); + if (!strv) { + updated = FALSE; + goto done; + } json_value = json_array (); for (i = 0; strv[i]; i++) json_array_append_new (json_value, json_string (strv[i])); - } else - return FALSE; - } else { + } else { + updated = FALSE; + goto done; + } + } else { /* G_VALUE_HOLDS_? */ g_assert_not_reached (); updated = FALSE; goto done; From 62876cee9a6bbafc8437d6f4274b32a48be2de0c Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Sun, 12 Nov 2017 00:08:03 +0100 Subject: [PATCH 08/23] libnm-core: synchronize team.link_watchers when team.config is set. (cherry picked from commit 363a2cfe957fcc39b616abc390a2aa934f14f46a) --- libnm-core/nm-setting-team.c | 3 ++ libnm-core/nm-utils-private.h | 24 ++++++++++ libnm-core/nm-utils.c | 89 +++++++++++++++++++++++++++++++++-- 3 files changed, 113 insertions(+), 3 deletions(-) diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c index d2a343803c..52e44cc17a 100644 --- a/libnm-core/nm-setting-team.c +++ b/libnm-core/nm-setting-team.c @@ -1351,6 +1351,9 @@ _align_team_properties (NMSettingTeam *setting) nm_setting_team_add_runner_tx_hash (setting, strv[i]); g_strfreev (strv); } + + g_ptr_array_unref (priv->link_watchers); + priv->link_watchers = JSON_TO_VAL (ptr_array, PROP_LINK_WATCHERS); } static void diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h index 31196694ca..b7fde275ed 100644 --- a/libnm-core/nm-utils-private.h +++ b/libnm-core/nm-utils-private.h @@ -162,6 +162,30 @@ _nm_utils_json_extract_strv (char *conf, return ret; } +static inline GPtrArray * +_nm_utils_json_extract_ptr_array (char *conf, + _NMUtilsTeamPropertyKeys key, + gboolean is_port) +{ + gs_free GValue *t_value = NULL; + GPtrArray *data, *ret; + guint i; + + ret = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); + t_value = _nm_utils_team_config_get (conf, key.key1, key.key2, key.key3, is_port); + if (!t_value) + return ret; + + data = g_value_get_boxed (t_value); + if (!data) + return ret; + + for (i = 0; i < data->len; i++) + g_ptr_array_add (ret, nm_team_link_watcher_dup (data->pdata[i])); + g_value_unset (t_value); + return ret; +} + static inline void _nm_utils_json_append_gvalue (char **conf, _NMUtilsTeamPropertyKeys key, diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 24c7a8ed6f..787bb59a60 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4302,6 +4302,14 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to) #if WITH_JANSSON +/* Added in Jansson v2.3 (released Jan 27 2012) */ +#ifndef json_object_foreach +#define json_object_foreach(object, key, value) \ + for(key = json_object_iter_key(json_object_iter(object)); \ + key && (value = json_object_iter_value(json_object_iter_at (object, key) )); \ + key = json_object_iter_key(json_object_iter_next(object, json_object_iter_at (object, key)))) +#endif + /* Added in Jansson v2.4 (released Sep 23 2012), but travis.ci has v2.2. */ #ifndef json_boolean #define json_boolean(val) ((val) ? json_true() : json_false()) @@ -4521,6 +4529,53 @@ key_already_there: json_decref (value); } +static NMTeamLinkWatcher * +_nm_utils_team_link_watcher_from_json (json_t *json_element) +{ + const char *j_key; + json_t *j_val; + gs_free char *name = NULL, *target_host = NULL, *source_host = NULL; + int val1 = 0, val2 = 0, val3 = 3; + NMTeamLinkWatcherArpPingFlags flags = 0; + + g_return_val_if_fail (json_element, NULL); + + json_object_foreach (json_element, j_key, j_val) { + if (nm_streq (j_key, "name")) + name = strdup (json_string_value (j_val)); + else if (nm_streq (j_key, "target_host")) + target_host = strdup (json_string_value (j_val)); + else if (nm_streq (j_key, "source_host")) + source_host = strdup (json_string_value (j_val)); + else if (NM_IN_STRSET (j_key, "delay_up", "init_wait")) + val1 = json_integer_value (j_val); + else if (NM_IN_STRSET (j_key, "delay_down", "interval")) + val2 = json_integer_value (j_val); + else if (nm_streq (j_key, "missed_max")) + val3 = json_integer_value (j_val); + else if (nm_streq (j_key, "validate_active")) { + if (json_is_true (j_val)) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE; + } else if (nm_streq (j_key, "validate_inactive")) { + if (json_is_true (j_val)) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE; + } else if (nm_streq (j_key, "send_always")) { + if (json_is_true (j_val)) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS; + } + } + + if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) + return nm_team_link_watcher_new_ethtool (val1, val2, NULL); + else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_NSNA_PING)) + return nm_team_link_watcher_new_nsna_ping (val1, val2, val3, target_host, NULL); + else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ARP_PING)) { + return nm_team_link_watcher_new_arp_ping (val1, val2, val3, target_host, + source_host, flags, NULL); + } else + return NULL; +} + GValue * _nm_utils_team_config_get (const char *conf, const char *key, @@ -4546,10 +4601,13 @@ _nm_utils_team_config_get (const char *conf, /* Some properties are added by teamd when missing from the initial * configuration. Add them with the default value if necessary, depending * on the configuration type. + * Skip this for port config, as some properties change on the basis of the + * runner specified in the master connection... but we don't want to check + * against properties in another connection. Moreover, for team-port we have + * the link-watchers property only here: and for this compound property it is + * fine to show the default value only if explicitly set. */ - if (port_config) { - _json_add_object (json, "link_watch", "name", NULL, json_string ("ethtool")); - } else { + if (!port_config) { /* Retrieve runner or add default one */ json_element = json_object_get (json, "runner"); if (json_element) { @@ -4595,6 +4653,31 @@ _nm_utils_team_config_get (const char *conf, } else if (json_is_boolean (json_element)) { g_value_init (value, G_TYPE_BOOLEAN); g_value_set_boolean (value, json_boolean_value (json_element)); + } else if (nm_streq (key, "link_watch")) { + NMTeamLinkWatcher *watcher; + GPtrArray *data = g_ptr_array_new_with_free_func + ((GDestroyNotify) nm_team_link_watcher_unref); + + if (json_is_array (json_element)) { + json_t *j_watcher; + int index; + + json_array_foreach (json_element, index, j_watcher) { + watcher = _nm_utils_team_link_watcher_from_json (j_watcher); + if (watcher) + g_ptr_array_add (data, watcher); + } + } else { + watcher = _nm_utils_team_link_watcher_from_json (json_element); + if (watcher) + g_ptr_array_add (data, watcher); + } + if (data->len) { + g_value_init (value, G_TYPE_PTR_ARRAY); + g_value_take_boxed (value, data); + } else + g_ptr_array_free (data, TRUE); + } else if (json_is_array (json_element)) { GPtrArray *data = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); json_t *str_element; From 10745107f24b7db1c75340f01185b89079182f1c Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Mon, 13 Nov 2017 17:57:46 +0100 Subject: [PATCH 09/23] libnm-core: add keyfile writer for team link watcher Allow tests to dump the content of the property when getting a failure. (cherry picked from commit 0d8fcc39abdf9efce71a91ff5091a6d729fd8b9e) --- libnm-core/nm-keyfile-writer.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libnm-core/nm-keyfile-writer.c b/libnm-core/nm-keyfile-writer.c index 30d519c40a..0efabf27a8 100644 --- a/libnm-core/nm-keyfile-writer.c +++ b/libnm-core/nm-keyfile-writer.c @@ -501,6 +501,15 @@ cert_writer (KeyfileWriterInfo *info, cert_writer_default (info->connection, info->keyfile, &type_data); } +static void +team_link_watcher_writer (KeyfileWriterInfo *info, + NMSetting *setting, + const char *key, + const GValue *value) +{ + /* skip */ +} + /*****************************************************************************/ typedef struct { @@ -576,6 +585,9 @@ static KeyWriter key_writers[] = { { NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, cert_writer }, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_LINK_WATCHERS, + team_link_watcher_writer}, { NULL, NULL, NULL } }; From 704f0acb77756020818ccc5d99f829096b135644 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Thu, 16 Nov 2017 18:54:06 +0100 Subject: [PATCH 10/23] libnm-core: team-port: expose the new link-watchers property It will allow explicit configuration of link-watchers in the team port configuration. (cherry picked from commit f094837d737c5e8d29f02790f2133d70e10222b0) --- clients/common/settings-docs.c.in | 1 + libnm-core/nm-setting-team-port.c | 237 +++++++++++++++++++++++++++++- libnm-core/nm-setting-team-port.h | 33 ++++- libnm/libnm.ver | 6 + 4 files changed, 262 insertions(+), 15 deletions(-) diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index 160fcfc720..9014cd4539 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -335,6 +335,7 @@ #define DESCRIBE_DOC_NM_SETTING_TEAM_PORT_CONFIG N_("The JSON configuration for the team port. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details.") #define DESCRIBE_DOC_NM_SETTING_TEAM_PORT_LACP_KEY N_("Corresponds to the teamd ports.PORTIFNAME.lacp_key.") #define DESCRIBE_DOC_NM_SETTING_TEAM_PORT_LACP_PRIO N_("Corresponds to the teamd ports.PORTIFNAME.lacp_prio.") +#define DESCRIBE_DOC_NM_SETTING_TEAM_PORT_LINK_WATCHERS N_("Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-incative', 'send-always'. See teamd.conf man for more details.") #define DESCRIBE_DOC_NM_SETTING_TEAM_PORT_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") #define DESCRIBE_DOC_NM_SETTING_TEAM_PORT_PRIO N_("Corresponds to the teamd ports.PORTIFNAME.prio.") #define DESCRIBE_DOC_NM_SETTING_TEAM_PORT_QUEUE_ID N_("Corresponds to the teamd ports.PORTIFNAME.queue_id. When set to -1 means the parameter is skipped from the json config.") diff --git a/libnm-core/nm-setting-team-port.c b/libnm-core/nm-setting-team-port.c index f97920dc38..5ab8f6916f 100644 --- a/libnm-core/nm-setting-team-port.c +++ b/libnm-core/nm-setting-team-port.c @@ -15,6 +15,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * + * Copyright 2017 Red Hat, Inc. * Copyright 2013 Jiri Pirko */ @@ -29,7 +30,6 @@ #include "nm-utils-private.h" #include "nm-connection-private.h" #include "nm-setting-connection.h" -#include "nm-setting-team.h" /** * SECTION:nm-setting-team-port @@ -52,6 +52,7 @@ typedef struct { gboolean sticky; int lacp_prio; int lacp_key; + GPtrArray *link_watchers; /* Array of NMTeamLinkWatcher */ } NMSettingTeamPortPrivate; /* Keep aligned with _prop_to_keys[] */ @@ -63,18 +64,20 @@ enum { PROP_STICKY, PROP_LACP_PRIO, PROP_LACP_KEY, + PROP_LINK_WATCHERS, LAST_PROP }; /* Keep aligned with team-port properties enum */ static const _NMUtilsTeamPropertyKeys _prop_to_keys[LAST_PROP] = { - [PROP_0] = { NULL, NULL, NULL, 0 }, - [PROP_CONFIG] = { NULL, NULL, NULL, 0 }, - [PROP_QUEUE_ID] = { "queue_id", NULL, NULL, NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT }, - [PROP_PRIO] = { "prio", NULL, NULL, 0 }, - [PROP_STICKY] = { "sticky", NULL, NULL, 0 }, - [PROP_LACP_PRIO] = { "lacp_prio", NULL, NULL, NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT }, - [PROP_LACP_KEY] = { "lacp_key", NULL, NULL, 0 }, + [PROP_0] = { NULL, NULL, NULL, 0 }, + [PROP_CONFIG] = { NULL, NULL, NULL, 0 }, + [PROP_QUEUE_ID] = { "queue_id", NULL, NULL, NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT }, + [PROP_PRIO] = { "prio", NULL, NULL, 0 }, + [PROP_STICKY] = { "sticky", NULL, NULL, 0 }, + [PROP_LACP_PRIO] = { "lacp_prio", NULL, NULL, NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT }, + [PROP_LACP_KEY] = { "lacp_key", NULL, NULL, 0 }, + [PROP_LINK_WATCHERS] = { "link_watch", NULL, NULL, 0 } }; @@ -185,6 +188,159 @@ nm_setting_team_port_get_lacp_key (NMSettingTeamPort *setting) return NM_SETTING_TEAM_PORT_GET_PRIVATE (setting)->lacp_key; } +/** + * nm_setting_team_port_get_num_link_watchers: + * @setting: the #NMSettingTeamPort + * + * Returns: the number of configured link watchers + * + * Since: 1.10.2 + **/ +guint +nm_setting_team_port_get_num_link_watchers (NMSettingTeamPort *setting) +{ + NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting); + + g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), 0); + + return priv->link_watchers->len; +} + +/** + * nm_setting_team_port_get_link_watcher: + * @setting: the #NMSettingTeamPort + * @idx: index number of the link watcher to return + * + * Returns: (transfer none): the link watcher at index @idx. + * + * Since: 1.10.2 + **/ +NMTeamLinkWatcher * +nm_setting_team_port_get_link_watcher (NMSettingTeamPort *setting, guint idx) +{ + NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting); + + g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), NULL); + g_return_val_if_fail (idx < priv->link_watchers->len, NULL); + + return priv->link_watchers->pdata[idx]; +} + +/** + * nm_setting_team_port_add_link_watcher: + * @setting: the #NMSettingTeamPort + * @link_watcher: the link watcher to add + * + * Appends a new link watcher to the setting. + * + * Returns: %TRUE if the link watcher is added; %FALSE if an identical link + * watcher was already there. + * + * Since: 1.10.2 + **/ +gboolean +nm_setting_team_port_add_link_watcher (NMSettingTeamPort *setting, + NMTeamLinkWatcher *link_watcher) +{ + NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting); + guint i; + + g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), FALSE); + g_return_val_if_fail (link_watcher != NULL, FALSE); + + for (i = 0; i < priv->link_watchers->len; i++) { + if (nm_team_link_watcher_equal (priv->link_watchers->pdata[i], link_watcher)) + return FALSE; + } + + g_ptr_array_add (priv->link_watchers, nm_team_link_watcher_dup (link_watcher)); + g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_PORT_LINK_WATCHERS); + return TRUE; +} + +/** + * nm_setting_team_port_remove_link_watcher: + * @setting: the #NMSettingTeamPort + * @idx: index number of the link watcher to remove + * + * Removes the link watcher at index #idx. + * + * Since: 1.10.2 + **/ +void +nm_setting_team_port_remove_link_watcher (NMSettingTeamPort *setting, guint idx) +{ + NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting); + + g_return_if_fail (NM_IS_SETTING_TEAM_PORT (setting)); + g_return_if_fail (idx < priv->link_watchers->len); + + g_ptr_array_remove_index (priv->link_watchers, idx); + g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_PORT_LINK_WATCHERS); +} + +/** + * nm_setting_team_port_remove_link_watcher_by_value: + * @setting: the #NMSettingTeamPort + * @link_watcher: the link watcher to remove + * + * Removes the link watcher entry matching link_watcher. + * + * Returns: %TRUE if the link watcher was found and removed, %FALSE otherwise. + * + * Since: 1.10.2 + **/ +gboolean +nm_setting_team_port_remove_link_watcher_by_value (NMSettingTeamPort *setting, + NMTeamLinkWatcher *link_watcher) +{ + NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting); + guint i; + + g_return_val_if_fail (NM_IS_SETTING_TEAM_PORT (setting), FALSE); + + for (i = 0; i < priv->link_watchers->len; i++) { + if (nm_team_link_watcher_equal (priv->link_watchers->pdata[i], link_watcher)) { + g_ptr_array_remove_index (priv->link_watchers, i); + g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_PORT_LINK_WATCHERS); + return TRUE; + } + } + return FALSE; +} + +/** + * nm_setting_team_port_clear_link_watchers: + * @setting: the #NMSettingTeamPort + * + * Removes all configured link watchers. + * + * Since: 1.10.2 + **/ +void +nm_setting_team_port_clear_link_watchers (NMSettingTeamPort *setting) +{ + NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting); + + g_return_if_fail (NM_IS_SETTING_TEAM_PORT (setting)); + + g_ptr_array_set_size (priv->link_watchers, 0); + g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_PORT_LINK_WATCHERS); +} + +static GVariant * +team_link_watchers_to_dbus (const GValue *prop_value) +{ + return _nm_utils_team_link_watchers_to_variant (g_value_get_boxed (prop_value)); +} + +static void +team_link_watchers_from_dbus (GVariant *dbus_value, + GValue *prop_value) +{ + g_value_take_boxed (prop_value, _nm_utils_team_link_watchers_from_variant (dbus_value)); +} + static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { @@ -253,6 +409,8 @@ compare_property (NMSetting *setting, NMSettingCompareFlags flags) { NMSettingClass *parent_class; + NMSettingTeamPortPrivate *a_priv, *b_priv; + guint i, j; /* If we are trying to match a connection in order to assume it (and thus * @flags contains INFERRABLE), use the "relaxed" matching for team @@ -265,6 +423,24 @@ compare_property (NMSetting *setting, NM_SETTING_TEAM_PORT_GET_PRIVATE (other)->config, TRUE); } + if (nm_streq0 (prop_spec->name, NM_SETTING_TEAM_PORT_LINK_WATCHERS)) { + a_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (setting); + b_priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (other); + + if (a_priv->link_watchers->len != b_priv->link_watchers->len) + return FALSE; + for (i = 0; i < a_priv->link_watchers->len; i++) { + for (j = 0; j < b_priv->link_watchers->len; j++) { + if (nm_team_link_watcher_equal (a_priv->link_watchers->pdata[i], + b_priv->link_watchers->pdata[j])) { + break; + } + } + if (j == b_priv->link_watchers->len) + return FALSE; + } + return TRUE; + } /* Otherwise chain up to parent to handle generic compare */ parent_class = NM_SETTING_CLASS (nm_setting_team_port_parent_class); @@ -278,6 +454,7 @@ nm_setting_team_port_init (NMSettingTeamPort *setting) priv->queue_id = NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT; priv->lacp_prio = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT; + priv->link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); } #define JSON_TO_VAL(typ, id) _nm_utils_json_extract_##typ (priv->config, _prop_to_keys[id], TRUE) @@ -299,6 +476,9 @@ set_property (GObject *object, guint prop_id, priv->sticky = JSON_TO_VAL (boolean, PROP_STICKY); priv->lacp_prio = JSON_TO_VAL (int, PROP_LACP_PRIO); priv->lacp_key = JSON_TO_VAL (int, PROP_LACP_KEY); + + g_ptr_array_unref (priv->link_watchers); + priv->link_watchers = JSON_TO_VAL (ptr_array, PROP_LINK_WATCHERS); break; case PROP_QUEUE_ID: if (priv->queue_id == g_value_get_int (value)) @@ -341,6 +521,15 @@ set_property (GObject *object, guint prop_id, align_value = value; align_config = TRUE; break; + case PROP_LINK_WATCHERS: + g_ptr_array_unref (priv->link_watchers); + priv->link_watchers = _nm_utils_copy_array (g_value_get_boxed (value), + (NMUtilsCopyFunc) nm_team_link_watcher_dup, + (GDestroyNotify) nm_team_link_watcher_unref); + if (priv->link_watchers->len) + align_value = value; + align_config = TRUE; + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -375,6 +564,11 @@ get_property (GObject *object, guint prop_id, case PROP_LACP_KEY: g_value_set_int (value, priv->lacp_key); break; + case PROP_LINK_WATCHERS: + g_value_take_boxed (value, _nm_utils_copy_array (priv->link_watchers, + (NMUtilsCopyFunc) nm_team_link_watcher_dup, + (GDestroyNotify) nm_team_link_watcher_unref)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -387,6 +581,7 @@ finalize (GObject *object) NMSettingTeamPortPrivate *priv = NM_SETTING_TEAM_PORT_GET_PRIVATE (object); g_free (priv->config); + g_ptr_array_unref (priv->link_watchers); G_OBJECT_CLASS (nm_setting_team_port_parent_class)->finalize (object); } @@ -500,5 +695,31 @@ nm_setting_team_port_class_init (NMSettingTeamPortClass *setting_class) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * NMSettingTeamPort:link-watchers: + * + * Link watchers configuration for the connection: each link watcher is + * defined by a dictionary, whose keys depend upon the selected link + * watcher. Available link watchers are 'ethtool', 'nsna_ping' and + * 'arp_ping' and it is specified in the dictionary with the key 'name'. + * Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; + * nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; + * arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', + * 'validate-incative', 'send-always'. See teamd.conf man for more details. + * + * Element-Type: NMTeamLinkWatcher + * Since: 1.10.2 + **/ + g_object_class_install_property + (object_class, PROP_LINK_WATCHERS, + g_param_spec_boxed (NM_SETTING_TEAM_PORT_LINK_WATCHERS, "", "", + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + _nm_setting_class_transform_property (parent_class, + NM_SETTING_TEAM_PORT_LINK_WATCHERS, + G_VARIANT_TYPE ("aa{sv}"), + team_link_watchers_to_dbus, + team_link_watchers_from_dbus); } diff --git a/libnm-core/nm-setting-team-port.h b/libnm-core/nm-setting-team-port.h index 825f648154..26b2e098cb 100644 --- a/libnm-core/nm-setting-team-port.h +++ b/libnm-core/nm-setting-team-port.h @@ -26,6 +26,7 @@ #endif #include "nm-setting.h" +#include "nm-setting-team.h" G_BEGIN_DECLS @@ -38,12 +39,13 @@ G_BEGIN_DECLS #define NM_SETTING_TEAM_PORT_SETTING_NAME "team-port" -#define NM_SETTING_TEAM_PORT_CONFIG "config" -#define NM_SETTING_TEAM_PORT_QUEUE_ID "queue-id" -#define NM_SETTING_TEAM_PORT_PRIO "prio" -#define NM_SETTING_TEAM_PORT_STICKY "sticky" -#define NM_SETTING_TEAM_PORT_LACP_PRIO "lacp-prio" -#define NM_SETTING_TEAM_PORT_LACP_KEY "lacp-key" +#define NM_SETTING_TEAM_PORT_CONFIG "config" +#define NM_SETTING_TEAM_PORT_QUEUE_ID "queue-id" +#define NM_SETTING_TEAM_PORT_PRIO "prio" +#define NM_SETTING_TEAM_PORT_STICKY "sticky" +#define NM_SETTING_TEAM_PORT_LACP_PRIO "lacp-prio" +#define NM_SETTING_TEAM_PORT_LACP_KEY "lacp-key" +#define NM_SETTING_TEAM_PORT_LINK_WATCHERS "link-watchers" #define NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT -1 #define NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT 255 @@ -79,7 +81,24 @@ NM_AVAILABLE_IN_1_10_2 gint nm_setting_team_port_get_lacp_prio (NMSettingTeamPort *setting); NM_AVAILABLE_IN_1_10_2 gint nm_setting_team_port_get_lacp_key (NMSettingTeamPort *setting); - +NM_AVAILABLE_IN_1_10_2 +guint nm_setting_team_port_get_num_link_watchers (NMSettingTeamPort *setting); +NM_AVAILABLE_IN_1_10_2 +NMTeamLinkWatcher * +nm_setting_team_port_get_link_watcher (NMSettingTeamPort *setting, guint idx); +NM_AVAILABLE_IN_1_10_2 +gboolean +nm_setting_team_port_add_link_watcher (NMSettingTeamPort *setting, + NMTeamLinkWatcher *link_watcher); +NM_AVAILABLE_IN_1_10_2 +void +nm_setting_team_port_remove_link_watcher (NMSettingTeamPort *setting, guint idx); +NM_AVAILABLE_IN_1_10_2 +gboolean +nm_setting_team_port_remove_link_watcher_by_value (NMSettingTeamPort *setting, + NMTeamLinkWatcher *link_watcher); +NM_AVAILABLE_IN_1_10_2 +void nm_setting_team_port_clear_link_watchers (NMSettingTeamPort *setting); G_END_DECLS #endif /* __NM_SETTING_TEAM_PORT_H__ */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index b8f071067c..7557089063 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1246,11 +1246,17 @@ global: nm_setting_team_get_runner_sys_prio; nm_setting_team_get_runner_min_ports; nm_setting_team_get_runner_agg_select_policy; + nm_setting_team_port_add_link_watcher; + nm_setting_team_port_clear_link_watchers; nm_setting_team_port_get_queue_id; nm_setting_team_port_get_prio; nm_setting_team_port_get_sticky; nm_setting_team_port_get_lacp_prio; nm_setting_team_port_get_lacp_key; + nm_setting_team_port_get_link_watcher; + nm_setting_team_port_get_num_link_watchers; + nm_setting_team_port_remove_link_watcher; + nm_setting_team_port_remove_link_watcher_by_value; nm_setting_team_remove_link_watcher; nm_setting_team_remove_link_watcher_by_value; nm_setting_team_remove_runner_tx_hash; From 07b1e8080371ecaa154011b6ba78b6b2a3589d9e Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Fri, 17 Nov 2017 14:50:56 +0100 Subject: [PATCH 11/23] cli: add support to TeamPort link watchers (cherry picked from commit c5228b8a8304d36816b61984f678e6e1bd99f4df) --- clients/common/nm-meta-setting-desc.c | 80 +++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 2febf9f2a2..98dc6d5e24 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -3923,6 +3923,78 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_team_link_watchers, nm_setting_team_remove_link_watcher, _validate_and_remove_team_link_watcher) +static gconstpointer +_get_fcn_team_port_link_watchers (ARGS_GET_FCN) +{ + NMSettingTeamPort *s_team_port = NM_SETTING_TEAM_PORT (setting); + GString *printable; + guint32 num_watchers, i; + NMTeamLinkWatcher *watcher; + char *watcher_str; + + RETURN_UNSUPPORTED_GET_TYPE (); + + printable = g_string_new (NULL); + + num_watchers = nm_setting_team_port_get_num_link_watchers (s_team_port); + for (i = 0; i < num_watchers; i++) { + watcher = nm_setting_team_port_get_link_watcher (s_team_port, i); + watcher_str = _dump_team_link_watcher (watcher); + if (watcher_str) { + if (printable->len > 0) + g_string_append (printable, ", "); + g_string_append (printable, watcher_str); + g_free (watcher_str); + } + } + + RETURN_STR_TO_FREE (g_string_free (printable, FALSE)); +} + +static gboolean +_set_fcn_team_port_link_watchers (ARGS_SET_FCN) +{ + gs_strfreev char **strv = NULL; + const char *const*iter; + NMTeamLinkWatcher *watcher; + + strv = nmc_strsplit_set (value, ",", 0); + for (iter = (const char *const*) strv; *iter; iter++) { + watcher = _parse_team_link_watcher (*iter, error); + if (!watcher) + return FALSE; + nm_setting_team_port_add_link_watcher (NM_SETTING_TEAM_PORT (setting), watcher); + nm_team_link_watcher_unref (watcher); + } + return TRUE; +} + +static gboolean +_validate_and_remove_team_port_link_watcher (NMSettingTeamPort *setting, + const char *watcher_str, + GError **error) +{ + NMTeamLinkWatcher *watcher; + gboolean ret; + + watcher = _parse_team_link_watcher (watcher_str, error); + if (!watcher) + return FALSE; + + ret = nm_setting_team_port_remove_link_watcher_by_value (setting, watcher); + if (!ret) { + g_set_error (error, 1, 0, _("the property doesn't contain link watcher '%s'"), + watcher_str); + } + nm_team_link_watcher_unref (watcher); + return ret; +} +DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_team_port_link_watchers, + NM_SETTING_TEAM_PORT, + nm_setting_team_port_get_num_link_watchers, + nm_setting_team_port_remove_link_watcher, + _validate_and_remove_team_port_link_watcher) + static gconstpointer _get_fcn_vlan_flags (ARGS_GET_FCN) { @@ -6494,6 +6566,14 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = { ), ), ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_TEAM_PORT_LINK_WATCHERS, + .describe_message = TEAM_LINK_WATCHERS_DESCRIBE_MESSAGE, + .property_type = DEFINE_PROPERTY_TYPE ( + .get_fcn = _get_fcn_team_port_link_watchers, + .set_fcn = _set_fcn_team_port_link_watchers, + .remove_fcn = _remove_fcn_team_port_link_watchers, + ), + ), NULL }; From e8eb4166755f188b11d40d757af4d350d85925b4 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Thu, 16 Nov 2017 19:34:54 +0100 Subject: [PATCH 12/23] libnm-core: use proper writer for team-port link-watchers (cherry picked from commit 16c9435c5b774d01e2dc16659ffb14a0b5fe921e) --- libnm-core/nm-keyfile-writer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libnm-core/nm-keyfile-writer.c b/libnm-core/nm-keyfile-writer.c index 0efabf27a8..d872419cd5 100644 --- a/libnm-core/nm-keyfile-writer.c +++ b/libnm-core/nm-keyfile-writer.c @@ -588,6 +588,9 @@ static KeyWriter key_writers[] = { { NM_SETTING_TEAM_SETTING_NAME, NM_SETTING_TEAM_LINK_WATCHERS, team_link_watcher_writer}, + { NM_SETTING_TEAM_PORT_SETTING_NAME, + NM_SETTING_TEAM_PORT_LINK_WATCHERS, + team_link_watcher_writer}, { NULL, NULL, NULL } }; From ad1be3a47295a3c511698790af3c81d365997a8a Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Wed, 15 Nov 2017 17:00:40 +0100 Subject: [PATCH 13/23] libnm-core: trivial: move json key deletion code to a separate function (cherry picked from commit 8648aa576ee321535f46de01e1a3e842953f7c49) --- libnm-core/nm-utils.c | 76 +++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 787bb59a60..6aac15021e 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4576,6 +4576,49 @@ _nm_utils_team_link_watcher_from_json (json_t *json_element) return NULL; } +/* + * Removes the specified key1[.key2.key3] from json. + * Returns TRUE if json has been modified, FALSE otherwise. */ +static gboolean +_json_del_object (json_t *json, + const char *key1, + const char *key2, + const char *key3) +{ + json_t *json_element = json; + json_t *json_link = NULL; + const char *iter_key = key1; + + if (key2) { + json_link = json; + json_element = json_object_get (json, key1); + if (!json_element) + return FALSE; + iter_key = key2; + } + if (key3) { + json_link = json_element; + json_element = json_object_get (json_element, key2); + if (!json_element) + return FALSE; + iter_key = key3; + } + if (json_object_del (json_element, iter_key) != 0) + return FALSE; + + /* 1st level key only */ + if (!json_link) + return TRUE; + + if (json_object_size (json_element) == 0) + json_object_del (json_link, (key3 ? key2 : key1)); + + if (key3 && json_object_size (json_link) == 0) + json_object_del (json, key1); + + return TRUE; +} + GValue * _nm_utils_team_config_get (const char *conf, const char *key, @@ -4796,38 +4839,7 @@ _nm_utils_team_config_set (char **conf, /* no new value? delete element */ if (!value) { - json_element = json; - json_link = NULL; - - if (key2) { - json_link = json; - json_element = json_object_get (json, key); - if (!json_element) - goto done; - iter_key = key2; - } - if (key3) { - json_link = json_element; - json_element = json_object_get (json_element, key2); - if (!json_element) - goto done; - iter_key = key3; - } - if (json_object_del (json_element, iter_key) != 0) - goto done; - - updated = TRUE; - - /* 1st level key only */ - if (!json_link) - goto done; - - if (json_object_size (json_element) == 0) - json_object_del (json_link, (key3 ? key2 : key)); - - if (key3 && json_object_size (json_link) == 0) - json_object_del (json, key); - + updated = _json_del_object (json, key, key2, key3); goto done; } From a2357fea43c0191d5193003bb2a4bd58a56cd781 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Wed, 15 Nov 2017 17:57:05 +0100 Subject: [PATCH 14/23] libnm-core: trivial: just move static json functions (cherry picked from commit f0ae71e7d687a52058f0c964047da6d8602e68e8) --- libnm-core/nm-utils.c | 422 +++++++++++++++++++++--------------------- 1 file changed, 211 insertions(+), 211 deletions(-) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 6aac15021e..eb45306e76 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4328,6 +4328,217 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to) #define json_boolean_value json_is_true #endif +static void +_json_add_object (json_t *json, + const char *key1, + const char *key2, + const char *key3, + json_t *value) +{ + json_t *json_element, *json_link; + + json_element = json_object_get (json, key1); + if (!json_element) { + json_element = value; + if (key2) { + if (key3) { + json_element = json_object (); + json_object_set_new (json_element, key3, value); + } + json_link = json_object (); + json_object_set_new (json_link, key2, json_element); + json_element = json_link; + } + json_object_set_new (json, key1, json_element); + return; + } + + if (!key2) + goto key_already_there; + + json_link = json_element; + json_element = json_object_get (json_element, key2); + if (!json_element) { + json_element = value; + if (key3) { + json_element = json_object (); + json_object_set_new (json_element, key3, value); + } + json_object_set_new (json_link, key2, json_element); + return; + } + + if (!key3) + goto key_already_there; + + json_link = json_element; + json_element = json_object_get (json_element, key3); + if (!json_element) { + json_object_set_new (json_link, key3, value); + return; + } + +key_already_there: + json_decref (value); +} + +/* + * Removes the specified key1[.key2.key3] from json. + * Returns TRUE if json has been modified, FALSE otherwise. */ +static gboolean +_json_del_object (json_t *json, + const char *key1, + const char *key2, + const char *key3) +{ + json_t *json_element = json; + json_t *json_link = NULL; + const char *iter_key = key1; + + if (key2) { + json_link = json; + json_element = json_object_get (json, key1); + if (!json_element) + return FALSE; + iter_key = key2; + } + if (key3) { + json_link = json_element; + json_element = json_object_get (json_element, key2); + if (!json_element) + return FALSE; + iter_key = key3; + } + + if (json_object_del (json_element, iter_key) != 0) + return FALSE; + + /* 1st level key only */ + if (!json_link) + return TRUE; + + if (json_object_size (json_element) == 0) + json_object_del (json_link, (key3 ? key2 : key1)); + + if (key3 && json_object_size (json_link) == 0) + json_object_del (json, key1); + + return TRUE; +} + +static NMTeamLinkWatcher * +_nm_utils_team_link_watcher_from_json (json_t *json_element) +{ + const char *j_key; + json_t *j_val; + gs_free char *name = NULL, *target_host = NULL, *source_host = NULL; + int val1 = 0, val2 = 0, val3 = 3; + NMTeamLinkWatcherArpPingFlags flags = 0; + + g_return_val_if_fail (json_element, NULL); + + json_object_foreach (json_element, j_key, j_val) { + if (nm_streq (j_key, "name")) + name = strdup (json_string_value (j_val)); + else if (nm_streq (j_key, "target_host")) + target_host = strdup (json_string_value (j_val)); + else if (nm_streq (j_key, "source_host")) + source_host = strdup (json_string_value (j_val)); + else if (NM_IN_STRSET (j_key, "delay_up", "init_wait")) + val1 = json_integer_value (j_val); + else if (NM_IN_STRSET (j_key, "delay_down", "interval")) + val2 = json_integer_value (j_val); + else if (nm_streq (j_key, "missed_max")) + val3 = json_integer_value (j_val); + else if (nm_streq (j_key, "validate_active")) { + if (json_is_true (j_val)) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE; + } else if (nm_streq (j_key, "validate_inactive")) { + if (json_is_true (j_val)) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE; + } else if (nm_streq (j_key, "send_always")) { + if (json_is_true (j_val)) + flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS; + } + } + + if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) + return nm_team_link_watcher_new_ethtool (val1, val2, NULL); + else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_NSNA_PING)) + return nm_team_link_watcher_new_nsna_ping (val1, val2, val3, target_host, NULL); + else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ARP_PING)) { + return nm_team_link_watcher_new_arp_ping (val1, val2, val3, target_host, + source_host, flags, NULL); + } else + return NULL; +} + +static json_t * +_nm_utils_team_link_watcher_to_json (NMTeamLinkWatcher *watcher) +{ + const char *name; + int int_val; + const char *str_val; + NMTeamLinkWatcherArpPingFlags flags = 0; + json_t *json_element; + + g_return_val_if_fail (watcher, NULL); + + json_element = json_object (); + name = nm_team_link_watcher_get_name (watcher); + if (!name) + goto fail; + + json_object_set_new (json_element, "name", json_string (name)); + + if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) { + int_val = nm_team_link_watcher_get_delay_up (watcher); + if (int_val) + json_object_set_new (json_element, "delay_up", json_integer (int_val)); + int_val = nm_team_link_watcher_get_delay_down (watcher); + if (int_val) + json_object_set_new (json_element, "delay_down", json_integer (int_val)); + return json_element; + } + + int_val = nm_team_link_watcher_get_init_wait (watcher); + if (int_val) + json_object_set_new (json_element, "init_wait", json_integer (int_val)); + int_val = nm_team_link_watcher_get_interval (watcher); + if (int_val) + json_object_set_new (json_element, "interval", json_integer (int_val)); + int_val = nm_team_link_watcher_get_missed_max (watcher); + if (int_val != 3) + json_object_set_new (json_element, "missed_max", json_integer (int_val)); + str_val = nm_team_link_watcher_get_target_host (watcher); + if (!str_val) + goto fail; + json_object_set_new (json_element, "target_host", json_string (str_val)); + + if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING)) + return json_element; + + str_val = nm_team_link_watcher_get_source_host (watcher); + if (!str_val) + goto fail; + json_object_set_new (json_element, "source_host", json_string (str_val)); + + flags = nm_team_link_watcher_get_flags (watcher); + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE) + json_object_set_new (json_element, "validate_active", json_string ("true")); + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE) + json_object_set_new (json_element, "validate_inactive", json_string ("true")); + if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS) + json_object_set_new (json_element, "send_always", json_string ("true")); + + return json_element; + +fail: + json_decref (json_element); + return NULL; +} + + /** * nm_utils_is_json_object: * @str: the JSON string to test @@ -4474,151 +4685,6 @@ out: } - -static void -_json_add_object (json_t *json, - const char *key1, - const char *key2, - const char *key3, - json_t *value) -{ - json_t *json_element, *json_link; - - json_element = json_object_get (json, key1); - if (!json_element) { - json_element = value; - if (key2) { - if (key3) { - json_element = json_object (); - json_object_set_new (json_element, key3, value); - } - json_link = json_object (); - json_object_set_new (json_link, key2, json_element); - json_element = json_link; - } - json_object_set_new (json, key1, json_element); - return; - } - - if (!key2) - goto key_already_there; - - json_link = json_element; - json_element = json_object_get (json_element, key2); - if (!json_element) { - json_element = value; - if (key3) { - json_element = json_object (); - json_object_set_new (json_element, key3, value); - } - json_object_set_new (json_link, key2, json_element); - return; - } - - if (!key3) - goto key_already_there; - - json_link = json_element; - json_element = json_object_get (json_element, key3); - if (!json_element) { - json_object_set_new (json_link, key3, value); - return; - } - -key_already_there: - json_decref (value); -} - -static NMTeamLinkWatcher * -_nm_utils_team_link_watcher_from_json (json_t *json_element) -{ - const char *j_key; - json_t *j_val; - gs_free char *name = NULL, *target_host = NULL, *source_host = NULL; - int val1 = 0, val2 = 0, val3 = 3; - NMTeamLinkWatcherArpPingFlags flags = 0; - - g_return_val_if_fail (json_element, NULL); - - json_object_foreach (json_element, j_key, j_val) { - if (nm_streq (j_key, "name")) - name = strdup (json_string_value (j_val)); - else if (nm_streq (j_key, "target_host")) - target_host = strdup (json_string_value (j_val)); - else if (nm_streq (j_key, "source_host")) - source_host = strdup (json_string_value (j_val)); - else if (NM_IN_STRSET (j_key, "delay_up", "init_wait")) - val1 = json_integer_value (j_val); - else if (NM_IN_STRSET (j_key, "delay_down", "interval")) - val2 = json_integer_value (j_val); - else if (nm_streq (j_key, "missed_max")) - val3 = json_integer_value (j_val); - else if (nm_streq (j_key, "validate_active")) { - if (json_is_true (j_val)) - flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE; - } else if (nm_streq (j_key, "validate_inactive")) { - if (json_is_true (j_val)) - flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE; - } else if (nm_streq (j_key, "send_always")) { - if (json_is_true (j_val)) - flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS; - } - } - - if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) - return nm_team_link_watcher_new_ethtool (val1, val2, NULL); - else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_NSNA_PING)) - return nm_team_link_watcher_new_nsna_ping (val1, val2, val3, target_host, NULL); - else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ARP_PING)) { - return nm_team_link_watcher_new_arp_ping (val1, val2, val3, target_host, - source_host, flags, NULL); - } else - return NULL; -} - -/* - * Removes the specified key1[.key2.key3] from json. - * Returns TRUE if json has been modified, FALSE otherwise. */ -static gboolean -_json_del_object (json_t *json, - const char *key1, - const char *key2, - const char *key3) -{ - json_t *json_element = json; - json_t *json_link = NULL; - const char *iter_key = key1; - - if (key2) { - json_link = json; - json_element = json_object_get (json, key1); - if (!json_element) - return FALSE; - iter_key = key2; - } - if (key3) { - json_link = json_element; - json_element = json_object_get (json_element, key2); - if (!json_element) - return FALSE; - iter_key = key3; - } - if (json_object_del (json_element, iter_key) != 0) - return FALSE; - - /* 1st level key only */ - if (!json_link) - return TRUE; - - if (json_object_size (json_element) == 0) - json_object_del (json_link, (key3 ? key2 : key1)); - - if (key3 && json_object_size (json_link) == 0) - json_object_del (json, key1); - - return TRUE; -} - GValue * _nm_utils_team_config_get (const char *conf, const char *key, @@ -4748,72 +4814,6 @@ _nm_utils_team_config_get (const char *conf, return value; } -static json_t * -_nm_utils_team_link_watcher_to_json (NMTeamLinkWatcher *watcher) -{ - const char *name; - int int_val; - const char *str_val; - NMTeamLinkWatcherArpPingFlags flags = 0; - json_t *json_element; - - g_return_val_if_fail (watcher, NULL); - - json_element = json_object (); - name = nm_team_link_watcher_get_name (watcher); - if (!name) - goto fail; - - json_object_set_new (json_element, "name", json_string (name)); - - if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) { - int_val = nm_team_link_watcher_get_delay_up (watcher); - if (int_val) - json_object_set_new (json_element, "delay_up", json_integer (int_val)); - int_val = nm_team_link_watcher_get_delay_down (watcher); - if (int_val) - json_object_set_new (json_element, "delay_down", json_integer (int_val)); - return json_element; - } - - int_val = nm_team_link_watcher_get_init_wait (watcher); - if (int_val) - json_object_set_new (json_element, "init_wait", json_integer (int_val)); - int_val = nm_team_link_watcher_get_interval (watcher); - if (int_val) - json_object_set_new (json_element, "interval", json_integer (int_val)); - int_val = nm_team_link_watcher_get_missed_max (watcher); - if (int_val != 3) - json_object_set_new (json_element, "missed_max", json_integer (int_val)); - str_val = nm_team_link_watcher_get_target_host (watcher); - if (!str_val) - goto fail; - json_object_set_new (json_element, "target_host", json_string (str_val)); - - if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING)) - return json_element; - - str_val = nm_team_link_watcher_get_source_host (watcher); - if (!str_val) - goto fail; - json_object_set_new (json_element, "source_host", json_string (str_val)); - - flags = nm_team_link_watcher_get_flags (watcher); - if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE) - json_object_set_new (json_element, "validate_active", json_string ("true")); - if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE) - json_object_set_new (json_element, "validate_inactive", json_string ("true")); - if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS) - json_object_set_new (json_element, "send_always", json_string ("true")); - - return json_element; - -fail: - json_decref (json_element); - return NULL; -} - - /* if conf is updated in place returns TRUE */ gboolean _nm_utils_team_config_set (char **conf, From dd18259c635d5baa946f578622c27f40086df68e Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Wed, 15 Nov 2017 18:23:57 +0100 Subject: [PATCH 15/23] libnm-core: json: share code to load defaults in team(-port).config Move code from _nm_utils_team_config_get to the brand new _json_team_add_defaults function without any change. Then remove the duplicated code from _nm_utils_team_config_equal and leverage the new function. Here the only functional change is that the defaults for "notify_peers" and "mcast_rejoin" for the "activebackup" runner are added (the only case in which their default values are different than 0). (cherry picked from commit fdd41852ee6688170c554eb2d76cbbd330f40f1d) --- libnm-core/nm-utils.c | 108 +++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 58 deletions(-) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index eb45306e76..a35609987a 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4426,6 +4426,50 @@ _json_del_object (json_t *json, return TRUE; } +/* Adds in place to json the defaults for missing properties */ +static void +_json_team_add_defaults (json_t *json, + gboolean port_config) +{ + json_t *json_element; + const char *runner = NULL; + + if (port_config) { + _json_add_object (json, "link_watch", "name", NULL, + json_string (NM_TEAM_LINK_WATCHER_ETHTOOL)); + } else { + /* Retrieve runner or add default one */ + json_element = json_object_get (json, "runner"); + if (json_element) { + runner = json_string_value (json_object_get (json_element, "name")); + } else { + json_element = json_object (); + json_object_set_new (json, "runner", json_element); + } + if (!runner) { + runner = NM_SETTING_TEAM_RUNNER_DEFAULT; + json_object_set_new (json_element, "name", json_string (runner)); + } + + + if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP)) { + _json_add_object (json, "notify_peers", "count", NULL, + json_integer (NM_SETTING_TEAM_NOTIFY_PEERS_COUNT_ACTIVEBACKUP_DEFAULT)); + _json_add_object (json, "mcast_rejoin", "count", NULL, + json_integer (NM_SETTING_TEAM_NOTIFY_MCAST_COUNT_ACTIVEBACKUP_DEFAULT)); + } else if ( nm_streq (runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE) + || nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) { + json_element = json_array (); + json_array_append_new (json_element, json_string ("eth")); + json_array_append_new (json_element, json_string ("ipv4")); + json_array_append_new (json_element, json_string ("ipv6")); + _json_add_object (json, "runner", "tx_hash", NULL, json_element); + } + } +} + + + static NMTeamLinkWatcher * _nm_utils_team_link_watcher_from_json (json_t *json_element) { @@ -4607,9 +4651,8 @@ _nm_utils_team_config_equal (const char *conf1, gboolean port_config) { json_t *json1 = NULL, *json2 = NULL, *json; - json_t *array, *name; gs_free char *dump1 = NULL, *dump2 = NULL; - json_t *value, *property; + json_t *value; json_error_t jerror; const char *key; gboolean ret; @@ -4633,33 +4676,8 @@ _nm_utils_team_config_equal (const char *conf1, * configuration. Add them with the default value if necessary, depending * on the configuration type. */ - for (i = 0, json = json1; i < 2; i++, json = json2) { - if (port_config) { - property = json_object_get (json, "link_watch"); - if (!property) { - property = json_object (); - json_object_set_new (property, "name", json_string ("ethtool")); - json_object_set_new (json, "link_watch", property); - } - } else { - property = json_object_get (json, "runner"); - if (!property) { - property = json_object (); - json_object_set_new (property, "name", json_string ("roundrobin")); - json_object_set_new (json, "runner", property); - } else if ( (name = json_object_get (property, "name")) - && NM_IN_STRSET (json_string_value (name), "lacp", "loadbalance")) { - /* Add default tx_hash when missing */ - if (!json_object_get (property, "tx_hash")) { - array = json_array (); - json_array_append_new (array, json_string ("eth")); - json_array_append_new (array, json_string ("ipv4")); - json_array_append_new (array, json_string ("ipv6")); - json_object_set_new (property, "tx_hash", array); - } - } - } - } + for (i = 0, json = json1; i < 2; i++, json = json2) + _json_team_add_defaults (json, port_config); /* Only consider a given subset of nodes, others can change depending on * current state */ @@ -4696,7 +4714,6 @@ _nm_utils_team_config_get (const char *conf, json_t *json_element; GValue *value = NULL; json_error_t jerror; - const char *runner = NULL; if (!key) return NULL; @@ -4716,35 +4733,10 @@ _nm_utils_team_config_get (const char *conf, * the link-watchers property only here: and for this compound property it is * fine to show the default value only if explicitly set. */ - if (!port_config) { - /* Retrieve runner or add default one */ - json_element = json_object_get (json, "runner"); - if (json_element) { - runner = json_string_value (json_object_get (json_element, "name")); - } else { - json_element = json_object (); - json_object_set_new (json, "runner", json_element); - } - if (!runner) { - runner = NM_SETTING_TEAM_RUNNER_DEFAULT; - json_object_set_new (json_element, "name", json_string (runner)); - } + if (!port_config) + _json_team_add_defaults (json, port_config); - - if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP)) { - _json_add_object (json, "notify_peers", "count", NULL, - json_integer (NM_SETTING_TEAM_NOTIFY_PEERS_COUNT_ACTIVEBACKUP_DEFAULT)); - _json_add_object (json, "mcast_rejoin", "count", NULL, - json_integer (NM_SETTING_TEAM_NOTIFY_MCAST_COUNT_ACTIVEBACKUP_DEFAULT)); - } else if ( nm_streq (runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE) - || nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) { - json_element = json_array (); - json_array_append_new (json_element, json_string ("eth")); - json_array_append_new (json_element, json_string ("ipv4")); - json_array_append_new (json_element, json_string ("ipv6")); - _json_add_object (json, "runner", "tx_hash", NULL, json_element); - } - } + /* Now search the property to retrieve */ json_element = json_object_get (json, key); if (json_element && key2) json_element = json_object_get (json_element, key2); From 07a49b30af2dedd5faaa86ae05f06001f96c48d9 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Tue, 28 Nov 2017 10:41:56 +0100 Subject: [PATCH 16/23] libnm-core: team: use the correct name for teamd property 'balancing_interval' the teamd 'runner.tx_balancer.balancing_interval' property was wrongly set and searched as 'runner.tx_balancer.interval'. Fixed. Fixes: fc3b7d61e29a56106a0ecb55deb7fcdcf7d9b691 (cherry picked from commit ed2a1a153b0952de701e962e357ddc3ab31ed6f0) --- libnm-core/nm-setting-team.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c index 52e44cc17a..16068a425d 100644 --- a/libnm-core/nm-setting-team.c +++ b/libnm-core/nm-setting-team.c @@ -623,7 +623,7 @@ static const _NMUtilsTeamPropertyKeys _prop_to_keys[LAST_PROP] = { [PROP_RUNNER_HWADDR_POLICY] = { "runner", "hwaddr_policy", NULL, 0 }, [PROP_RUNNER_TX_HASH] = { "runner", "tx_hash", NULL, 0 }, [PROP_RUNNER_TX_BALANCER] = { "runner", "tx_balancer", "name", 0 }, - [PROP_RUNNER_TX_BALANCER_INTERVAL] = { "runner", "tx_balancer", "interval", + [PROP_RUNNER_TX_BALANCER_INTERVAL] = { "runner", "tx_balancer", "balancing_interval", NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT }, [PROP_RUNNER_ACTIVE] = { "runner", "active", NULL, 0 }, [PROP_RUNNER_FAST_RATE] = { "runner", "fast_rate", NULL, 0 }, From 5d79b6cc42bea50279beca4cc494d935086e5faa Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Tue, 21 Nov 2017 16:15:32 +0100 Subject: [PATCH 17/23] libnm-core: team: rework defaults management on runner properties till now when no explicit value was set on a property, the default value for that property was returned, also if the property was not applicable to the selected runner. Fix this, showing default values for properties only when relevant and showing instead -1 or null when the property is not relevant for the selected runner. Moreover, reset all the properties but the link-watchers when the team.runner is changed: this is required to clean up the properties unrelated to the new runner and start with the runner-specific defaults. (cherry picked from commit a5642fd93a2f6927002ea95f649c77ca5202ba18) --- libnm-core/nm-setting-team.c | 74 +++++------- libnm-core/nm-utils.c | 216 ++++++++++++++++++++++++++++++----- 2 files changed, 218 insertions(+), 72 deletions(-) diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c index 16068a425d..03e6ba4bda 100644 --- a/libnm-core/nm-setting-team.c +++ b/libnm-core/nm-setting-team.c @@ -623,15 +623,12 @@ static const _NMUtilsTeamPropertyKeys _prop_to_keys[LAST_PROP] = { [PROP_RUNNER_HWADDR_POLICY] = { "runner", "hwaddr_policy", NULL, 0 }, [PROP_RUNNER_TX_HASH] = { "runner", "tx_hash", NULL, 0 }, [PROP_RUNNER_TX_BALANCER] = { "runner", "tx_balancer", "name", 0 }, - [PROP_RUNNER_TX_BALANCER_INTERVAL] = { "runner", "tx_balancer", "balancing_interval", - NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT }, + [PROP_RUNNER_TX_BALANCER_INTERVAL] = { "runner", "tx_balancer", "balancing_interval", -1 }, [PROP_RUNNER_ACTIVE] = { "runner", "active", NULL, 0 }, [PROP_RUNNER_FAST_RATE] = { "runner", "fast_rate", NULL, 0 }, - [PROP_RUNNER_SYS_PRIO] = { "runner", "sys_prio", NULL, - NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT }, - [PROP_RUNNER_MIN_PORTS] = { "runner", "min_ports", NULL, 0 }, - [PROP_RUNNER_AGG_SELECT_POLICY] = { "runner", "agg_select_policy", NULL, - {.default_str = NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT} }, + [PROP_RUNNER_SYS_PRIO] = { "runner", "sys_prio", NULL, -1 }, + [PROP_RUNNER_MIN_PORTS] = { "runner", "min_ports", NULL, -1 }, + [PROP_RUNNER_AGG_SELECT_POLICY] = { "runner", "agg_select_policy", NULL, 0 }, [PROP_LINK_WATCHERS] = { "link_watch", NULL, NULL, 0 } }; @@ -1289,8 +1286,9 @@ nm_setting_team_init (NMSettingTeam *setting) NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); priv->runner = g_strdup (NM_SETTING_TEAM_RUNNER_ROUNDROBIN); - priv->runner_sys_prio = NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT; - priv->runner_tx_balancer_interval = NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT; + priv->runner_tx_balancer_interval = -1; + priv->runner_sys_prio = -1; + priv->runner_min_ports = -1; priv->link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); } @@ -1376,51 +1374,45 @@ set_property (GObject *object, guint prop_id, if (priv->notify_peers_count == g_value_get_int (value)) break; priv->notify_peers_count = g_value_get_int (value); - if (priv->notify_peers_count) - align_value = value; + align_value = value; align_config = TRUE; break; case PROP_NOTIFY_PEERS_INTERVAL: if (priv->notify_peers_interval == g_value_get_int (value)) break; priv->notify_peers_interval = g_value_get_int (value); - if (priv->notify_peers_interval) - align_value = value; + align_value = value; align_config = TRUE; break; case PROP_MCAST_REJOIN_COUNT: if (priv->mcast_rejoin_count == g_value_get_int (value)) break; priv->mcast_rejoin_count = g_value_get_int (value); - if (priv->mcast_rejoin_count) - align_value = value; + align_value = value; align_config = TRUE; break; case PROP_MCAST_REJOIN_INTERVAL: if (priv->mcast_rejoin_interval == g_value_get_int (value)) break; priv->mcast_rejoin_interval = g_value_get_int (value); - if (priv->mcast_rejoin_interval) - align_value = value; + align_value = value; align_config = TRUE; break; case PROP_RUNNER: + if ( !g_value_get_string (value) + || nm_streq (priv->runner, g_value_get_string (value))) + break; g_free (priv->runner); priv->runner = g_value_dup_string (value); - if ( priv->runner - && !nm_streq (priv->runner, - NM_SETTING_TEAM_RUNNER_DEFAULT)) - align_value = value; - align_config = TRUE; + _nm_utils_json_append_gvalue (&priv->config, _prop_to_keys[prop_id], value); + _align_team_properties (setting); break; case PROP_RUNNER_HWADDR_POLICY: + if (nm_streq0 (priv->runner_hwaddr_policy, g_value_get_string (value))) + break; g_free (priv->runner_hwaddr_policy); priv->runner_hwaddr_policy = g_value_dup_string (value); - if ( priv->runner_hwaddr_policy - && !nm_streq (priv->runner_hwaddr_policy, - NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_SAME_ALL)) { - align_value = value; - } + align_value = value; align_config = TRUE; break; case PROP_RUNNER_TX_HASH: @@ -1435,60 +1427,54 @@ set_property (GObject *object, guint prop_id, align_config = TRUE; break; case PROP_RUNNER_TX_BALANCER: + if (nm_streq0 (priv->runner_tx_balancer, g_value_get_string (value))) + break; g_free (priv->runner_tx_balancer); priv->runner_tx_balancer = g_value_dup_string (value); - if (priv->runner_tx_balancer) - align_value = value; + align_value = value; align_config = TRUE; break; case PROP_RUNNER_TX_BALANCER_INTERVAL: if (priv->runner_tx_balancer_interval == g_value_get_int (value)) break; priv->runner_tx_balancer_interval = g_value_get_int (value); - if (priv->runner_tx_balancer_interval != - NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT) - align_value = value; + align_value = value; align_config = TRUE; break; case PROP_RUNNER_ACTIVE: if (priv->runner_active == g_value_get_boolean (value)) break; priv->runner_active = g_value_get_boolean (value); - if (priv->runner_active) - align_value = value; + align_value = value; align_config = TRUE; break; case PROP_RUNNER_FAST_RATE: if (priv->runner_fast_rate == g_value_get_boolean (value)) break; priv->runner_fast_rate = g_value_get_boolean (value); - if (priv->runner_fast_rate) - align_value = value; + align_value = value; align_config = TRUE; break; case PROP_RUNNER_SYS_PRIO: if (priv->runner_sys_prio == g_value_get_int (value)) break; priv->runner_sys_prio = g_value_get_int (value); - if (priv->runner_sys_prio != NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT) - align_value = value; + align_value = value; align_config = TRUE; break; case PROP_RUNNER_MIN_PORTS: if (priv->runner_min_ports == g_value_get_int (value)) break; priv->runner_min_ports = g_value_get_int (value); - if (priv->runner_min_ports) - align_value = value; + align_value = value; align_config = TRUE; break; case PROP_RUNNER_AGG_SELECT_POLICY: + if (nm_streq0 (priv->runner_agg_select_policy, g_value_get_string (value))) + break; g_free (priv->runner_agg_select_policy); priv->runner_agg_select_policy = g_value_dup_string (value); - if ( priv->runner_agg_select_policy - && !nm_streq (priv->runner_agg_select_policy, - NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_LACP_PRIO)) - align_value = value; + align_value = value; align_config = TRUE; break; case PROP_LINK_WATCHERS: diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index a35609987a..5d83890a20 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4426,10 +4426,13 @@ _json_del_object (json_t *json, return TRUE; } -/* Adds in place to json the defaults for missing properties */ +/* Adds in place to json the defaults for missing properties; + * the "add_implicit" allows to add to the json also the default + * values used but not shown with teamdctl */ static void _json_team_add_defaults (json_t *json, - gboolean port_config) + gboolean port_config, + gboolean add_implicit) { json_t *json_element; const char *runner = NULL; @@ -4437,38 +4440,193 @@ _json_team_add_defaults (json_t *json, if (port_config) { _json_add_object (json, "link_watch", "name", NULL, json_string (NM_TEAM_LINK_WATCHER_ETHTOOL)); + return; + } + + /* Retrieve runner or add default one */ + json_element = json_object_get (json, "runner"); + if (json_element) { + runner = json_string_value (json_object_get (json_element, "name")); } else { - /* Retrieve runner or add default one */ - json_element = json_object_get (json, "runner"); - if (json_element) { - runner = json_string_value (json_object_get (json_element, "name")); - } else { - json_element = json_object (); - json_object_set_new (json, "runner", json_element); - } - if (!runner) { - runner = NM_SETTING_TEAM_RUNNER_DEFAULT; - json_object_set_new (json_element, "name", json_string (runner)); - } + json_element = json_object (); + json_object_set_new (json, "runner", json_element); + } + if (!runner) { + runner = NM_SETTING_TEAM_RUNNER_DEFAULT; + json_object_set_new (json_element, "name", json_string (runner)); + } - if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP)) { - _json_add_object (json, "notify_peers", "count", NULL, - json_integer (NM_SETTING_TEAM_NOTIFY_PEERS_COUNT_ACTIVEBACKUP_DEFAULT)); - _json_add_object (json, "mcast_rejoin", "count", NULL, - json_integer (NM_SETTING_TEAM_NOTIFY_MCAST_COUNT_ACTIVEBACKUP_DEFAULT)); - } else if ( nm_streq (runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE) - || nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) { - json_element = json_array (); - json_array_append_new (json_element, json_string ("eth")); - json_array_append_new (json_element, json_string ("ipv4")); - json_array_append_new (json_element, json_string ("ipv6")); - _json_add_object (json, "runner", "tx_hash", NULL, json_element); + if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP)) { + _json_add_object (json, "notify_peers", "count", NULL, + json_integer (NM_SETTING_TEAM_NOTIFY_PEERS_COUNT_ACTIVEBACKUP_DEFAULT)); + _json_add_object (json, "mcast_rejoin", "count", NULL, + json_integer (NM_SETTING_TEAM_NOTIFY_MCAST_COUNT_ACTIVEBACKUP_DEFAULT)); + } else if ( nm_streq (runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE) + || nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) { + json_element = json_array (); + json_array_append_new (json_element, json_string ("eth")); + json_array_append_new (json_element, json_string ("ipv4")); + json_array_append_new (json_element, json_string ("ipv6")); + _json_add_object (json, "runner", "tx_hash", NULL, json_element); + } + + if (!add_implicit) + return; + + if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP)) + _json_add_object (json, "runner", "hwaddr_policy", NULL, json_string ("same_all")); + else if (NM_IN_STRSET (runner, + NM_SETTING_TEAM_RUNNER_LOADBALANCE, + NM_SETTING_TEAM_RUNNER_LACP)) { + _json_add_object (json, "runner", "tx_balancer", "balancing_interval", + json_integer (NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT)); + if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) { + _json_add_object (json, "runner", "active", NULL, json_boolean (TRUE)); + _json_add_object (json, "runner", "sys_prio", NULL, + json_integer (NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT)); + _json_add_object (json, "runner", "min_ports", NULL, json_integer (0)); + _json_add_object (json, "runner", "agg_select_policy", NULL, + json_string (NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT)); } } } +static json_t * +_json_find_object (json_t *json, + const char *key1, + const char *key2, + const char *key3) +{ + json_t *json_element; + if (!key1) + return NULL; + json_element = json_object_get (json, key1); + if (!key2 || !json_element) + return json_element; + + json_element = json_object_get (json_element, key2); + if (!key3 || !json_element) + return json_element; + + json_element = json_object_get (json_element, key3); + return json_element; +} + +static inline void +_json_delete_object_on_int_match (json_t *json, + const char *key1, + const char *key2, + const char *key3, + int val) +{ + json_t *json_element; + + json_element = _json_find_object (json, key1, key2, key3); + if (!json_element || !json_is_integer (json_element)) + return; + if (json_integer_value (json_element) == val) + _json_del_object (json, key1, key2, key3); +} + +static inline void +_json_delete_object_on_bool_match (json_t *json, + const char *key1, + const char *key2, + const char *key3, + gboolean val) +{ + json_t *json_element; + + json_element = _json_find_object (json, key1, key2, key3); + if (!json_element || !json_is_boolean (json_element)) + return; + if (json_boolean_value (json_element) == val) + _json_del_object (json, key1, key2, key3); +} + +static inline void +_json_delete_object_on_string_match (json_t *json, + const char *key1, + const char *key2, + const char *key3, + const char *val) +{ + json_t *json_element; + + json_element = _json_find_object (json, key1, key2, key3); + if (!json_element || !json_is_string (json_element)) + return; + if (nm_streq0 (json_string_value (json_element), val)) + _json_del_object (json, key1, key2, key3); +} + +static void +_json_team_normalize_defaults (json_t *json, gboolean reset) +{ + json_t *json_element; + const char *runner = NM_SETTING_TEAM_RUNNER_DEFAULT; + int notify_peers_count = 0, notify_peers_interval = 0; + int mcast_rejoin_count = 0, mcast_rejoin_interval = 0; + int runner_tx_balancer_interval = -1; + gboolean runner_active = FALSE, runner_fast_rate = FALSE; + int runner_sys_prio = -1, runner_min_ports = -1; + + json_element = _json_find_object (json, "runner", "name", NULL); + if (json_element) { + runner = json_string_value (json_element); + _json_delete_object_on_string_match (json, "runner", "name", NULL, + NM_SETTING_TEAM_RUNNER_DEFAULT); + } + + /* the runner changed: clear all the properties. Then team.config will be saved + * and reloaded triggering the reset of the values through _nm_utils_team_config_get + */ + if (reset) { + _json_del_object (json, "notify_peers", "count", NULL); + _json_del_object (json, "notify_peers", "interval", NULL); + _json_del_object (json, "mcast_rejoin", "count", NULL); + _json_del_object (json, "mcast_rejoin", "interval", NULL); + _json_del_object (json, "runner", "hwaddr_policy", NULL); + _json_del_object (json, "runner", "tx_hash", NULL); + _json_del_object (json, "runner", "tx_balancer", "name"); + _json_del_object (json, "runner", "tx_balancer", "balancing_interval"); + _json_del_object (json, "runner", "active", NULL); + _json_del_object (json, "runner", "fast_rate", NULL); + _json_del_object (json, "runner", "sys_prio", NULL); + _json_del_object (json, "runner", "min_ports", NULL); + _json_del_object (json, "runner", "agg_select_policy", NULL); + return; + } + + if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP)) { + notify_peers_count = 1; + mcast_rejoin_count = 1; + _json_delete_object_on_string_match (json, "runner", "hwaddr_policy", NULL, + NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_DEFAULT); + } else if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_LACP)) { + runner_tx_balancer_interval = 50; + runner_active = TRUE; + runner_sys_prio = 255; + runner_min_ports = 0; + _json_delete_object_on_string_match (json, "runner", "agg_select_policy", NULL, + NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT); + } else if (nm_streq (runner, NM_SETTING_TEAM_RUNNER_LOADBALANCE)) + runner_tx_balancer_interval = 50; + + _json_delete_object_on_int_match (json, "notify_peers", "count", NULL, notify_peers_count); + _json_delete_object_on_int_match (json, "notify_peers", "interval", NULL, notify_peers_interval); + _json_delete_object_on_int_match (json, "mcast_rejoin", "count", NULL, mcast_rejoin_count); + _json_delete_object_on_int_match (json, "macst_rejoin", "interval", NULL, mcast_rejoin_interval); + _json_delete_object_on_int_match (json, "runner", "tx_balancer", "balancing_interval", + runner_tx_balancer_interval); + _json_delete_object_on_int_match (json, "runner", "sys_prio", NULL, runner_sys_prio); + _json_delete_object_on_int_match (json, "runner", "min_ports", NULL, runner_min_ports); + _json_delete_object_on_bool_match (json, "runner", "active", NULL, runner_active); + _json_delete_object_on_bool_match (json, "runner", "active", NULL, runner_active); + _json_delete_object_on_bool_match (json, "runner", "fast_rate", NULL, runner_fast_rate); +} static NMTeamLinkWatcher * _nm_utils_team_link_watcher_from_json (json_t *json_element) @@ -4677,7 +4835,7 @@ _nm_utils_team_config_equal (const char *conf1, * on the configuration type. */ for (i = 0, json = json1; i < 2; i++, json = json2) - _json_team_add_defaults (json, port_config); + _json_team_add_defaults (json, port_config, FALSE); /* Only consider a given subset of nodes, others can change depending on * current state */ @@ -4734,7 +4892,7 @@ _nm_utils_team_config_get (const char *conf, * fine to show the default value only if explicitly set. */ if (!port_config) - _json_team_add_defaults (json, port_config); + _json_team_add_defaults (json, port_config, TRUE); /* Now search the property to retrieve */ json_element = json_object_get (json, key); @@ -4921,6 +5079,8 @@ _nm_utils_team_config_set (char **conf, done: if (updated) { + _json_team_normalize_defaults (json, ( nm_streq0 (key, "runner") + && nm_streq0 (key2, "name"))); g_free (*conf); *conf = json_dumps (json, JSON_PRESERVE_ORDER); /* Don't save an empty config */ From 4525b7e208ff6d3f925c3c8014f35e2f52520aa4 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Wed, 6 Dec 2017 23:15:07 +0100 Subject: [PATCH 18/23] libnm-core: team: change tx-hash APIs idx type from int to guint (cherry picked from commit 4c7a84182358170fe7939f378ab51d1e836c7122) --- libnm-core/nm-setting-team.c | 8 ++++---- libnm-core/nm-setting-team.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c index 03e6ba4bda..24078a0057 100644 --- a/libnm-core/nm-setting-team.c +++ b/libnm-core/nm-setting-team.c @@ -927,12 +927,12 @@ nm_setting_team_get_num_runner_tx_hash (NMSettingTeam *setting) * Since: 1.10.2 **/ const char * -nm_setting_team_get_runner_tx_hash (NMSettingTeam *setting, int idx) +nm_setting_team_get_runner_tx_hash (NMSettingTeam *setting, guint idx) { NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), NULL); - g_return_val_if_fail (idx >= 0 && idx < priv->runner_tx_hash->len, NULL); + g_return_val_if_fail (idx < priv->runner_tx_hash->len, NULL); return priv->runner_tx_hash->pdata[idx]; } @@ -947,12 +947,12 @@ nm_setting_team_get_runner_tx_hash (NMSettingTeam *setting, int idx) * Since: 1.10.2 **/ void -nm_setting_team_remove_runner_tx_hash (NMSettingTeam *setting, int idx) +nm_setting_team_remove_runner_tx_hash (NMSettingTeam *setting, guint idx) { NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); g_return_if_fail (NM_IS_SETTING_TEAM (setting)); - g_return_if_fail (idx >= 0 && idx < priv->runner_tx_hash->len); + g_return_if_fail (idx < priv->runner_tx_hash->len); g_ptr_array_remove_index (priv->runner_tx_hash, idx); g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_RUNNER_TX_HASH); diff --git a/libnm-core/nm-setting-team.h b/libnm-core/nm-setting-team.h index fe30c5a3a4..4520783632 100644 --- a/libnm-core/nm-setting-team.h +++ b/libnm-core/nm-setting-team.h @@ -206,9 +206,9 @@ gboolean nm_setting_team_remove_runner_tx_hash_by_value (NMSettingTeam *setting, NM_AVAILABLE_IN_1_10_2 guint nm_setting_team_get_num_runner_tx_hash (NMSettingTeam *setting); NM_AVAILABLE_IN_1_10_2 -const char *nm_setting_team_get_runner_tx_hash (NMSettingTeam *setting, int idx); +const char *nm_setting_team_get_runner_tx_hash (NMSettingTeam *setting, guint idx); NM_AVAILABLE_IN_1_10_2 -void nm_setting_team_remove_runner_tx_hash (NMSettingTeam *setting, int idx); +void nm_setting_team_remove_runner_tx_hash (NMSettingTeam *setting, guint idx); NM_AVAILABLE_IN_1_10_2 gboolean nm_setting_team_add_runner_tx_hash (NMSettingTeam *setting, const char *txhash); NM_AVAILABLE_IN_1_10_2 From bc92380a761cd6933531aa507c13fc384fbf3d04 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Wed, 6 Dec 2017 17:52:56 +0100 Subject: [PATCH 19/23] libnm-core: team: skip writing in the keyfile all the exposed properties Their values are already saved in the team.config and team-port.config properties, from which they are synced. (cherry picked from commit bb4c95e16863276eee1b5b094bc96a223f32c668) --- libnm-core/nm-keyfile-writer.c | 69 +++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/libnm-core/nm-keyfile-writer.c b/libnm-core/nm-keyfile-writer.c index d872419cd5..236dad8027 100644 --- a/libnm-core/nm-keyfile-writer.c +++ b/libnm-core/nm-keyfile-writer.c @@ -502,10 +502,10 @@ cert_writer (KeyfileWriterInfo *info, } static void -team_link_watcher_writer (KeyfileWriterInfo *info, - NMSetting *setting, - const char *key, - const GValue *value) +null_writer (KeyfileWriterInfo *info, + NMSetting *setting, + const char *key, + const GValue *value) { /* skip */ } @@ -585,12 +585,69 @@ static KeyWriter key_writers[] = { { NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, cert_writer }, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_NOTIFY_PEERS_COUNT, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_MCAST_REJOIN_COUNT, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_RUNNER, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_RUNNER_HWADDR_POLICY, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_RUNNER_TX_HASH, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_RUNNER_TX_BALANCER, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_RUNNER_ACTIVE, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_RUNNER_FAST_RATE, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_RUNNER_SYS_PRIO, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_RUNNER_MIN_PORTS, + null_writer}, + { NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY, + null_writer}, { NM_SETTING_TEAM_SETTING_NAME, NM_SETTING_TEAM_LINK_WATCHERS, - team_link_watcher_writer}, + null_writer}, + { NM_SETTING_TEAM_PORT_SETTING_NAME, + NM_SETTING_TEAM_PORT_QUEUE_ID, + null_writer}, + { NM_SETTING_TEAM_PORT_SETTING_NAME, + NM_SETTING_TEAM_PORT_PRIO, + null_writer}, + { NM_SETTING_TEAM_PORT_SETTING_NAME, + NM_SETTING_TEAM_PORT_STICKY, + null_writer}, + { NM_SETTING_TEAM_PORT_SETTING_NAME, + NM_SETTING_TEAM_PORT_LACP_PRIO, + null_writer}, + { NM_SETTING_TEAM_PORT_SETTING_NAME, + NM_SETTING_TEAM_PORT_LACP_KEY, + null_writer}, { NM_SETTING_TEAM_PORT_SETTING_NAME, NM_SETTING_TEAM_PORT_LINK_WATCHERS, - team_link_watcher_writer}, + null_writer}, { NULL, NULL, NULL } }; From bb3fc9769b3f24f35e457e6882a193ecb46551ed Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sun, 3 Dec 2017 13:37:39 +0100 Subject: [PATCH 20/23] libnm-core: merge the settings tests into a single one Thomas likes this more and who am I to argue. (cherry picked from commit 9bb30f86ec7e8fc993005623eac3597d384f6e8a) --- Makefile.am | 16 +- libnm-core/tests/test-setting-8021x.c | 404 ------------ libnm-core/tests/test-setting-bond.c | 247 ------- libnm-core/tests/test-setting-dcb.c | 321 --------- libnm-core/tests/test-setting.c | 899 ++++++++++++++++++++++++++ 5 files changed, 903 insertions(+), 984 deletions(-) delete mode 100644 libnm-core/tests/test-setting-8021x.c delete mode 100644 libnm-core/tests/test-setting-bond.c delete mode 100644 libnm-core/tests/test-setting-dcb.c create mode 100644 libnm-core/tests/test-setting.c diff --git a/Makefile.am b/Makefile.am index 1764bb2504..467ce2a83d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -639,9 +639,7 @@ check_programs += \ libnm-core/tests/test-general \ libnm-core/tests/test-keyfile \ libnm-core/tests/test-secrets \ - libnm-core/tests/test-setting-8021x \ - libnm-core/tests/test-setting-bond \ - libnm-core/tests/test-setting-dcb \ + libnm-core/tests/test-setting \ libnm-core/tests/test-settings-defaults GLIB_GENERATED += \ @@ -665,9 +663,7 @@ libnm_core_tests_test_crypto_CPPFLAGS = $(libnm_core_tests_cppflags) libnm_core_tests_test_general_CPPFLAGS = $(libnm_core_tests_cppflags) libnm_core_tests_test_keyfile_CPPFLAGS = $(libnm_core_tests_cppflags) libnm_core_tests_test_secrets_CPPFLAGS = $(libnm_core_tests_cppflags) -libnm_core_tests_test_setting_8021x_CPPFLAGS = $(libnm_core_tests_cppflags) -libnm_core_tests_test_setting_bond_CPPFLAGS = $(libnm_core_tests_cppflags) -libnm_core_tests_test_setting_dcb_CPPFLAGS = $(libnm_core_tests_cppflags) +libnm_core_tests_test_setting_CPPFLAGS = $(libnm_core_tests_cppflags) libnm_core_tests_test_settings_defaults_CPPFLAGS = $(libnm_core_tests_cppflags) libnm_core_tests_test_general_SOURCES = \ @@ -687,9 +683,7 @@ libnm_core_tests_test_crypto_LDADD = $(libnm_core_tests_ldadd) libnm_core_tests_test_general_LDADD = $(libnm_core_tests_ldadd) libnm_core_tests_test_keyfile_LDADD = $(libnm_core_tests_ldadd) libnm_core_tests_test_secrets_LDADD = $(libnm_core_tests_ldadd) -libnm_core_tests_test_setting_8021x_LDADD = $(libnm_core_tests_ldadd) -libnm_core_tests_test_setting_bond_LDADD = $(libnm_core_tests_ldadd) -libnm_core_tests_test_setting_dcb_LDADD = $(libnm_core_tests_ldadd) +libnm_core_tests_test_setting_LDADD = $(libnm_core_tests_ldadd) libnm_core_tests_test_settings_defaults_LDADD = $(libnm_core_tests_ldadd) $(libnm_core_tests_test_compare_OBJECTS): $(libnm_core_lib_h_pub_mkenums) @@ -697,9 +691,7 @@ $(libnm_core_tests_test_crypto_OBJECTS): $(libnm_core_lib_h_pub_mkenums) $(libnm_core_tests_test_general_OBJECTS): $(libnm_core_lib_h_pub_mkenums) $(libnm_core_tests_test_keyfile_OBJECTS): $(libnm_core_lib_h_pub_mkenums) $(libnm_core_tests_test_secrets_OBJECTS): $(libnm_core_lib_h_pub_mkenums) -$(libnm_core_tests_test_setting_8021x_OBJECTS): $(libnm_core_lib_h_pub_mkenums) -$(libnm_core_tests_test_setting_bond_OBJECTS): $(libnm_core_lib_h_pub_mkenums) -$(libnm_core_tests_test_setting_dcb_OBJECTS): $(libnm_core_lib_h_pub_mkenums) +$(libnm_core_tests_test_setting_OBJECTS): $(libnm_core_lib_h_pub_mkenums) $(libnm_core_tests_test_settings_defaults_OBJECTS): $(libnm_core_lib_h_pub_mkenums) # test-cert.p12 created with: diff --git a/libnm-core/tests/test-setting-8021x.c b/libnm-core/tests/test-setting-8021x.c deleted file mode 100644 index 268a9f52d9..0000000000 --- a/libnm-core/tests/test-setting-8021x.c +++ /dev/null @@ -1,404 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright 2008 - 2011 Red Hat, Inc. - * - */ - -#include "nm-default.h" - -#include - -#include "nm-utils.h" -#include "nm-setting-connection.h" -#include "nm-setting-8021x.h" - -#include "nm-utils/nm-test-utils.h" - -static void -compare_blob_data (const char *test, - const char *key_path, - GBytes *key) -{ - char *contents = NULL; - gsize len = 0; - GError *error = NULL; - gboolean success; - - g_assert (key && g_bytes_get_size (key) > 0); - - success = g_file_get_contents (key_path, &contents, &len, &error); - nmtst_assert_success (success, error); - - g_assert_cmpmem (contents, len, g_bytes_get_data (key, NULL), g_bytes_get_size (key)); - - g_free (contents); -} - -static void -check_scheme_path (GBytes *value, const char *path) -{ - const guint8 *p; - - g_assert (value); - - p = g_bytes_get_data (value, NULL); - g_assert (memcmp (p, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)) == 0); - p += strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH); - g_assert (memcmp (p, path, strlen (path)) == 0); - p += strlen (path); - g_assert (*p == '\0'); -} - -static void -test_private_key_import (const char *path, - const char *password, - NMSetting8021xCKScheme scheme) -{ - NMSetting8021x *s_8021x; - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - NMSetting8021xCKFormat tmp_fmt; - GError *error = NULL; - GBytes *tmp_key = NULL, *client_cert = NULL; - const char *pw; - - s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); - g_assert (s_8021x); - - success = nm_setting_802_1x_set_private_key (s_8021x, - path, - password, - scheme, - &format, - &error); - nmtst_assert_success (success, error); - g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); - tmp_fmt = nm_setting_802_1x_get_private_key_format (s_8021x); - g_assert (tmp_fmt == format); - - /* Make sure the password is what we expect */ - pw = nm_setting_802_1x_get_private_key_password (s_8021x); - g_assert (pw != NULL); - g_assert_cmpstr (pw, ==, password); - - if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { - tmp_key = nm_setting_802_1x_get_private_key_blob (s_8021x); - compare_blob_data ("private-key-import", path, tmp_key); - } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { - g_object_get (s_8021x, NM_SETTING_802_1X_PRIVATE_KEY, &tmp_key, NULL); - check_scheme_path (tmp_key, path); - g_bytes_unref (tmp_key); - } else - g_assert_not_reached (); - - /* If it's PKCS#12 ensure the client cert is the same value */ - if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) { - g_object_get (s_8021x, NM_SETTING_802_1X_PRIVATE_KEY, &tmp_key, NULL); - g_assert (tmp_key); - - g_object_get (s_8021x, NM_SETTING_802_1X_CLIENT_CERT, &client_cert, NULL); - g_assert (client_cert); - - /* make sure they are the same */ - g_assert (g_bytes_equal (tmp_key, client_cert)); - - g_bytes_unref (tmp_key); - g_bytes_unref (client_cert); - } - - g_object_unref (s_8021x); -} - -static void -test_phase2_private_key_import (const char *path, - const char *password, - NMSetting8021xCKScheme scheme) -{ - NMSetting8021x *s_8021x; - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - NMSetting8021xCKFormat tmp_fmt; - GError *error = NULL; - GBytes *tmp_key = NULL, *client_cert = NULL; - const char *pw; - - s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); - g_assert (s_8021x); - - success = nm_setting_802_1x_set_phase2_private_key (s_8021x, - path, - password, - scheme, - &format, - &error); - nmtst_assert_success (success, error); - g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); - tmp_fmt = nm_setting_802_1x_get_phase2_private_key_format (s_8021x); - g_assert (tmp_fmt == format); - - /* Make sure the password is what we expect */ - pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x); - g_assert (pw); - g_assert_cmpstr (pw, ==, password); - - if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { - tmp_key = nm_setting_802_1x_get_phase2_private_key_blob (s_8021x); - compare_blob_data ("phase2-private-key-import", path, tmp_key); - } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { - g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &tmp_key, NULL); - check_scheme_path (tmp_key, path); - g_bytes_unref (tmp_key); - } else - g_assert_not_reached (); - - /* If it's PKCS#12 ensure the client cert is the same value */ - if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) { - g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &tmp_key, NULL); - g_assert (tmp_key); - - g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, &client_cert, NULL); - g_assert (client_cert); - - /* make sure they are the same */ - g_assert (g_bytes_equal (tmp_key, client_cert)); - - g_bytes_unref (tmp_key); - g_bytes_unref (client_cert); - } - - g_object_unref (s_8021x); -} - -static void -test_wrong_password_keeps_data (const char *path, const char *password) -{ - NMSetting8021x *s_8021x; - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - GError *error = NULL; - const char *pw; - - s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); - g_assert (s_8021x); - - success = nm_setting_802_1x_set_private_key (s_8021x, - path, - password, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - &error); - nmtst_assert_success (success, error); - g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); - - /* Now try to set it to something that's not a certificate */ - format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - success = nm_setting_802_1x_set_private_key (s_8021x, - "Makefile.am", - password, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - &error); - nmtst_assert_no_success (success, error); - g_assert (format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); - g_clear_error (&error); - - /* Make sure the password hasn't changed */ - pw = nm_setting_802_1x_get_private_key_password (s_8021x); - g_assert (pw); - g_assert_cmpstr (pw, ==, password); - - g_object_unref (s_8021x); -} - -static void -test_clear_private_key (const char *path, const char *password) -{ - NMSetting8021x *s_8021x; - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - GError *error = NULL; - const char *pw; - - s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); - g_assert (s_8021x); - - success = nm_setting_802_1x_set_private_key (s_8021x, - path, - password, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - &error); - nmtst_assert_success (success, error); - g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); - - /* Make sure the password is what we expect */ - pw = nm_setting_802_1x_get_private_key_password (s_8021x); - g_assert (pw); - g_assert_cmpstr (pw, ==, password); - - /* Now clear it */ - success = nm_setting_802_1x_set_private_key (s_8021x, - NULL, - NULL, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - NULL, - &error); - nmtst_assert_success (success, error); - - /* Ensure the password is also now clear */ - g_assert (!nm_setting_802_1x_get_private_key_password (s_8021x)); - - g_object_unref (s_8021x); -} - -static void -test_wrong_phase2_password_keeps_data (const char *path, const char *password) -{ - NMSetting8021x *s_8021x; - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - GError *error = NULL; - const char *pw; - - s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); - g_assert (s_8021x); - - success = nm_setting_802_1x_set_phase2_private_key (s_8021x, - path, - password, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - &error); - nmtst_assert_success (success, error); - g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); - - /* Now try to set it to something that's not a certificate */ - format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - success = nm_setting_802_1x_set_phase2_private_key (s_8021x, - "Makefile.am", - password, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - &error); - nmtst_assert_no_success (success, error); - g_assert (format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); - g_clear_error (&error); - - /* Make sure the password hasn't changed */ - pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x); - g_assert (pw); - g_assert_cmpstr (pw, ==, password); - - g_object_unref (s_8021x); -} - -static void -test_clear_phase2_private_key (const char *path, const char *password) -{ - NMSetting8021x *s_8021x; - gboolean success; - NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - GError *error = NULL; - const char *pw; - - s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); - g_assert (s_8021x); - - success = nm_setting_802_1x_set_phase2_private_key (s_8021x, - path, - password, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - &format, - &error); - nmtst_assert_success (success, error); - g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); - - /* Make sure the password is what we expect */ - pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x); - g_assert (pw); - g_assert_cmpstr (pw, ==, password); - - /* Now clear it */ - success = nm_setting_802_1x_set_phase2_private_key (s_8021x, - NULL, - NULL, - NM_SETTING_802_1X_CK_SCHEME_BLOB, - NULL, - &error); - nmtst_assert_success (success, error); - - /* Ensure the password is also now clear */ - g_assert (!nm_setting_802_1x_get_phase2_private_key_password (s_8021x)); - - g_object_unref (s_8021x); -} - -static void -do_8021x_test (gconstpointer test_data) -{ - char **parts, *path, *password; - - parts = g_strsplit ((const char *) test_data, ", ", -1); - g_assert_cmpint (g_strv_length (parts), ==, 2); - - path = g_build_filename (TEST_CERT_DIR, parts[0], NULL); - password = parts[1]; - - /* Test phase1 and phase2 path scheme */ - test_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_PATH); - test_phase2_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_PATH); - - /* Test phase1 and phase2 blob scheme */ - test_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_BLOB); - test_phase2_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_BLOB); - - /* Test that using a wrong password does not change existing data */ - test_wrong_password_keeps_data (path, password); - test_wrong_phase2_password_keeps_data (path, password); - - /* Test clearing the private key */ - test_clear_private_key (path, password); - test_clear_phase2_private_key (path, password); - - g_free (path); - g_strfreev (parts); -} - -NMTST_DEFINE (); - -int -main (int argc, char **argv) -{ - nmtst_init (&argc, &argv, TRUE); - - g_test_add_data_func ("/libnm/setting-8021x/key-and-cert", - "test_key_and_cert.pem, test", - do_8021x_test); - g_test_add_data_func ("/libnm/setting-8021x/key-only", - "test-key-only.pem, test", - do_8021x_test); - g_test_add_data_func ("/libnm/setting-8021x/pkcs8-enc-key", - "pkcs8-enc-key.pem, 1234567890", - do_8021x_test); - g_test_add_data_func ("/libnm/setting-8021x/pkcs12", - "test-cert.p12, test", - do_8021x_test); - - return g_test_run (); -} - diff --git a/libnm-core/tests/test-setting-bond.c b/libnm-core/tests/test-setting-bond.c deleted file mode 100644 index e6a65bba64..0000000000 --- a/libnm-core/tests/test-setting-bond.c +++ /dev/null @@ -1,247 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright 2016 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-utils.h" -#include "nm-setting-bond.h" -#include "nm-connection.h" -#include "nm-simple-connection.h" -#include "nm-setting-connection.h" -#include "nm-errors.h" - -#include "nm-utils/nm-test-utils.h" - -static void -create_bond_connection (NMConnection **con, NMSettingBond **s_bond) -{ - NMSettingConnection *s_con; - - g_assert (con); - g_assert (s_bond); - - *con = nmtst_create_minimal_connection ("bond", - NULL, - NM_SETTING_BOND_SETTING_NAME, - &s_con); - g_assert (*con); - g_assert (s_con); - - g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, "bond0", NULL); - - *s_bond = (NMSettingBond *) nm_setting_bond_new (); - g_assert (*s_bond); - - nm_connection_add_setting (*con, NM_SETTING (*s_bond)); -} - -#define test_verify_options(exp, ...) \ - G_STMT_START { \ - const char *__opts[] = { __VA_ARGS__ , NULL }; \ - \ - _test_verify_options (__opts, exp); \ - } G_STMT_END - -static void -_test_verify_options (const char **options, gboolean expected_result) -{ - gs_unref_object NMConnection *con = NULL; - NMSettingBond *s_bond; - GError *error = NULL; - gboolean success; - const char **option; - - create_bond_connection (&con, &s_bond); - - for (option = options; option[0] && option[1]; option += 2) - g_assert (nm_setting_bond_add_option (s_bond, option[0], option[1])); - - if (expected_result) { - nmtst_assert_connection_verifies_and_normalizable (con); - nmtst_connection_normalize (con); - success = nm_setting_verify ((NMSetting *) s_bond, con, &error); - nmtst_assert_success (success, error); - } else { - nmtst_assert_connection_unnormalizable (con, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY); - } -} - -static void -test_verify (void) -{ - test_verify_options (TRUE, - "mode", "3", - "arp_interval", "0"); - test_verify_options (FALSE, - /* arp_interval not supported in balance-alb mode */ - "mode", "balance-alb", - "arp_interval", "1", - "arp_ip_target", "1.2.3.4"); - test_verify_options (FALSE, - /* arp_ip_target requires arp_interval */ - "mode", "balance-rr", - "arp_ip_target", "1.2.3.4"); - test_verify_options (TRUE, - "mode", "balance-rr", - "arp_interval", "1", - "arp_ip_target", "1.2.3.4"); - test_verify_options (FALSE, - /* num_grat_arp, num_unsol_na cannot be different */ - "mode", "balance-rr", - "num_grat_arp", "3", - "num_unsol_na", "4"); - test_verify_options (TRUE, - "mode", "balance-rr", - "num_grat_arp", "5", - "num_unsol_na", "5"); - test_verify_options (TRUE, - "mode", "active-backup", - "primary", "eth0"); - test_verify_options (FALSE, - /* primary requires mode=active-backup */ - "mode", "802.3ad", - "primary", "eth0"); - test_verify_options (TRUE, - "mode", "802.3ad", - "lacp_rate", "fast"); - test_verify_options (FALSE, - /* lacp_rate=fast requires mode=802.3ad */ - "mode", "balance-rr", - "lacp_rate", "fast"); - test_verify_options (TRUE, - "mode", "802.3ad", - "ad_actor_system", "ae:00:11:33:44:55"); -} - -static void -test_compare_options (gboolean exp_res, const char **opts1, const char **opts2) -{ - gs_unref_object NMSettingBond *s_bond1 = NULL, *s_bond2 = NULL; - const char **p; - - s_bond1 = (NMSettingBond *) nm_setting_bond_new (); - g_assert (s_bond1); - s_bond2 = (NMSettingBond *) nm_setting_bond_new (); - g_assert (s_bond2); - - for (p = opts1; p[0] && p[1]; p += 2) - g_assert (nm_setting_bond_add_option (s_bond1, p[0], p[1])); - - for (p = opts2; p[0] && p[1]; p += 2) - g_assert (nm_setting_bond_add_option (s_bond2, p[0], p[1])); - - g_assert_cmpint (nm_setting_compare ((NMSetting *) s_bond1, - (NMSetting *) s_bond2, - NM_SETTING_COMPARE_FLAG_EXACT), - ==, - exp_res); -} - -static void -test_compare (void) -{ - test_compare_options (TRUE, - ((const char *[]){ "mode", "balance-rr", "miimon", "1", NULL }), - ((const char *[]){ "mode", "balance-rr", "miimon", "1", NULL })); - test_compare_options (FALSE, - ((const char *[]){ "mode", "balance-rr", "miimon", "1", NULL }), - ((const char *[]){ "mode", "balance-rr", "miimon", "2", NULL })); - - /* ignore default values */ - test_compare_options (TRUE, - ((const char *[]){ "miimon", "1", NULL }), - ((const char *[]){ "miimon", "1", "updelay", "0", NULL })); - - /* special handling of num_grat_arp, num_unsol_na */ - test_compare_options (FALSE, - ((const char *[]){ "num_grat_arp", "2", NULL }), - ((const char *[]){ "num_grat_arp", "1", NULL })); - test_compare_options (TRUE, - ((const char *[]){ "num_grat_arp", "3", NULL }), - ((const char *[]){ "num_unsol_na", "3", NULL })); - test_compare_options (TRUE, - ((const char *[]){ "num_grat_arp", "4", NULL }), - ((const char *[]){ "num_unsol_na", "4", "num_grat_arp", "4", NULL })); -} - -static void -test_normalize_options (const char **opts1, const char **opts2) -{ - gs_unref_object NMConnection *con = NULL; - NMSettingBond *s_bond; - GError *error = NULL; - gboolean success; - const char **p; - int num = 0; - - create_bond_connection (&con, &s_bond); - - for (p = opts1; p[0] && p[1]; p += 2) - g_assert (nm_setting_bond_add_option (s_bond, p[0], p[1])); - - nmtst_assert_connection_verifies_and_normalizable (con); - nmtst_connection_normalize (con); - success = nm_setting_verify ((NMSetting *) s_bond, con, &error); - nmtst_assert_success (success, error); - - for (p = opts2; p[0] && p[1]; p += 2) { - g_assert_cmpstr (nm_setting_bond_get_option_by_name (s_bond, p[0]), ==, p[1]); - num++; - } - - g_assert_cmpint (num, ==, nm_setting_bond_get_num_options (s_bond)); -} - -static void -test_normalize (void) -{ - test_normalize_options ( - ((const char *[]){ "mode", "802.3ad", "ad_actor_system", "00:02:03:04:05:06", NULL }), - ((const char *[]){ "mode", "802.3ad", "ad_actor_system", "00:02:03:04:05:06", NULL })); - test_normalize_options ( - ((const char *[]){ "mode", "1", "miimon", "1", NULL }), - ((const char *[]){ "mode", "active-backup", "miimon", "1", NULL })); - test_normalize_options ( - ((const char *[]){ "mode", "balance-alb", "tlb_dynamic_lb", "1", NULL }), - ((const char *[]){ "mode", "balance-alb", NULL })); - test_normalize_options ( - ((const char *[]){ "mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL }), - ((const char *[]){ "mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL })); - test_normalize_options ( - ((const char *[]){ "mode", "balance-rr", "ad_actor_sys_prio", "4", "packets_per_slave", "3", NULL }), - ((const char *[]){ "mode", "balance-rr", "packets_per_slave", "3", NULL })); -} - -#define TPATH "/libnm/settings/bond/" - -NMTST_DEFINE (); - -int -main (int argc, char **argv) -{ - nmtst_init (&argc, &argv, TRUE); - - g_test_add_func (TPATH "verify", test_verify); - g_test_add_func (TPATH "compare", test_compare); - g_test_add_func (TPATH "normalize", test_normalize); - - return g_test_run (); -} diff --git a/libnm-core/tests/test-setting-dcb.c b/libnm-core/tests/test-setting-dcb.c deleted file mode 100644 index 55c1c5162c..0000000000 --- a/libnm-core/tests/test-setting-dcb.c +++ /dev/null @@ -1,321 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright 2013 Red Hat, Inc. - * - */ - -#include "nm-default.h" - -#include - -#include "nm-utils.h" -#include "nm-setting-dcb.h" -#include "nm-connection.h" -#include "nm-errors.h" - -#include "nm-utils/nm-test-utils.h" - -#define DCB_FLAGS_ALL (NM_SETTING_DCB_FLAG_ENABLE | \ - NM_SETTING_DCB_FLAG_ADVERTISE | \ - NM_SETTING_DCB_FLAG_WILLING) - -static void -test_dcb_flags_valid (void) -{ - gs_unref_object NMSettingDcb *s_dcb = NULL; - GError *error = NULL; - gboolean success; - guint i; - - s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); - g_assert (s_dcb); - - g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, 0); - g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, 0); - g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, 0); - g_assert_cmpint (nm_setting_dcb_get_priority_flow_control_flags (s_dcb), ==, 0); - g_assert_cmpint (nm_setting_dcb_get_priority_group_flags (s_dcb), ==, 0); - - g_object_set (G_OBJECT (s_dcb), - NM_SETTING_DCB_APP_FCOE_FLAGS, DCB_FLAGS_ALL, - NM_SETTING_DCB_APP_ISCSI_FLAGS, DCB_FLAGS_ALL, - NM_SETTING_DCB_APP_FIP_FLAGS, DCB_FLAGS_ALL, - NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, DCB_FLAGS_ALL, - NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, DCB_FLAGS_ALL, - NULL); - /* Priority Group Bandwidth must total 100% */ - for (i = 0; i < 7; i++) - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, i, 12); - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16); - - success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); - g_assert_no_error (error); - g_assert (success); - - g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, DCB_FLAGS_ALL); - g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, DCB_FLAGS_ALL); - g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, DCB_FLAGS_ALL); - g_assert_cmpint (nm_setting_dcb_get_priority_flow_control_flags (s_dcb), ==, DCB_FLAGS_ALL); - g_assert_cmpint (nm_setting_dcb_get_priority_group_flags (s_dcb), ==, DCB_FLAGS_ALL); -} - -#define TEST_FLAG(p, f, v) \ -{ \ - /* GObject property min/max should ensure the property does not get set to \ - * the invalid value, so we ensure the value we just tried to set is 0 and \ - * that verify is successful since the property never got set. \ - */ \ - g_object_set (G_OBJECT (s_dcb), p, v, NULL); \ - g_assert_cmpint (f (s_dcb), ==, 0); \ - success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ - g_assert_no_error (error); \ - g_assert (success); \ -} - -static void -test_dcb_flags_invalid (void) -{ - gs_unref_object NMSettingDcb *s_dcb = NULL; - GError *error = NULL; - gboolean success; - - s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); - g_assert (s_dcb); - - g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*"); - TEST_FLAG (NM_SETTING_DCB_APP_FCOE_FLAGS, nm_setting_dcb_get_app_fcoe_flags, 0x332523); - g_test_assert_expected_messages (); - - g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*"); - TEST_FLAG (NM_SETTING_DCB_APP_ISCSI_FLAGS, nm_setting_dcb_get_app_iscsi_flags, 0xFF); - g_test_assert_expected_messages (); - - g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*"); - TEST_FLAG (NM_SETTING_DCB_APP_FIP_FLAGS, nm_setting_dcb_get_app_fip_flags, 0x1111); - g_test_assert_expected_messages (); - - g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*"); - TEST_FLAG (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, nm_setting_dcb_get_priority_flow_control_flags, G_MAXUINT32); - g_test_assert_expected_messages (); - - g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*"); - TEST_FLAG (NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, nm_setting_dcb_get_priority_group_flags, - (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE | NM_SETTING_DCB_FLAG_WILLING) + 1); - g_test_assert_expected_messages (); -} - -#define TEST_APP_PRIORITY(lcprop, ucprop, v) \ -{ \ - g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_FLAGS, NM_SETTING_DCB_FLAG_NONE, NULL); \ - \ - g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_PRIORITY, v, NULL); \ - g_assert_cmpint (nm_setting_dcb_get_app_##lcprop##_priority (s_dcb), ==, v); \ - \ - /* Assert that the setting is invalid while the app is disabled unless v is default */ \ - success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ - if (v >= 0) { \ - g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); \ - g_assert (success == FALSE); \ - } else { \ - g_assert_no_error (error); \ - g_assert (success); \ - } \ - g_clear_error (&error); \ - \ - /* Set the enable flag and re-verify, this time it should be valid */ \ - g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL); \ - success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ - g_assert_no_error (error); \ - g_assert (success); \ - \ - g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_PRIORITY, 0, NULL); \ -} - -static void -test_dcb_app_priorities (void) -{ - gs_unref_object NMSettingDcb *s_dcb = NULL; - GError *error = NULL; - gboolean success; - - s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); - g_assert (s_dcb); - - /* Defaults */ - g_assert_cmpint (nm_setting_dcb_get_app_fcoe_priority (s_dcb), ==, -1); - g_assert_cmpint (nm_setting_dcb_get_app_iscsi_priority (s_dcb), ==, -1); - g_assert_cmpint (nm_setting_dcb_get_app_fip_priority (s_dcb), ==, -1); - - TEST_APP_PRIORITY (fcoe, FCOE, 6); - TEST_APP_PRIORITY (iscsi, ISCSI, 5); - TEST_APP_PRIORITY (fip, FIP, 4); - - TEST_APP_PRIORITY (fcoe, FCOE, -1); - TEST_APP_PRIORITY (iscsi, ISCSI, -1); - TEST_APP_PRIORITY (fip, FIP, -1); -} - -#define TEST_PRIORITY_VALID(fn, id, val, flagsprop, verify) \ -{ \ - /* Assert that setting the value gets the same value back out */ \ - nm_setting_dcb_set_priority_##fn (s_dcb, id, val); \ - g_assert_cmpint (nm_setting_dcb_get_priority_##fn (s_dcb, id), ==, val); \ - \ - if (verify) { \ - if (val != 0) { \ - /* Assert that verify fails because the flags do not include 'enabled' \ - * and a value has been set. \ - */ \ - success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ - g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); \ - g_assert (success == FALSE); \ - g_clear_error (&error); \ - } \ - \ - /* Assert that adding the 'enabled' flag verifies the setting */ \ - g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_##flagsprop##_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL); \ - success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ - g_assert_no_error (error); \ - g_assert (success); \ - } \ - \ - /* Reset everything */ \ - g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_##flagsprop##_FLAGS, NM_SETTING_DCB_FLAG_NONE, NULL); \ - nm_setting_dcb_set_priority_##fn (s_dcb, id, 0); \ -} - -/* If Priority Groups are enabled, PG bandwidth must equal 100% */ -#define SET_VALID_PRIORITY_GROUP_BANDWIDTH \ -{ \ - guint x; \ - for (x = 0; x < 7; x++) \ - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, x, 12); \ - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16); \ -} - -static void -test_dcb_priorities_valid (void) -{ - gs_unref_object NMSettingDcb *s_dcb = NULL; - GError *error = NULL; - gboolean success; - guint i; - - s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); - g_assert (s_dcb); - - for (i = 0; i < 8; i++) - TEST_PRIORITY_VALID (flow_control, i, TRUE, FLOW_CONTROL, TRUE); - - SET_VALID_PRIORITY_GROUP_BANDWIDTH - for (i = 0; i < 8; i++) { - TEST_PRIORITY_VALID (group_id, i, i, GROUP, TRUE); - TEST_PRIORITY_VALID (group_id, i, 7 - i, GROUP, TRUE); - } - - /* Clear PG bandwidth from earlier tests */ - for (i = 0; i < 8; i++) - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, i, 0); - - /* Priority Group Bandwidth must add up to 100% if enabled, which requires - * some dancing for verifying individual values here. - */ - for (i = 0; i < 8; i++) { - guint other = 7 - (i % 8); - - /* Set another priority group to the remaining bandwidth */ - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 100 - i); - TEST_PRIORITY_VALID (group_bandwidth, i, i, GROUP, TRUE); - - /* Set another priority group to the remaining bandwidth */ - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 100 - (7 - i)); - TEST_PRIORITY_VALID (group_bandwidth, i, 7 - i, GROUP, TRUE); - - /* Clear remaining bandwidth */ - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 0); - } - - SET_VALID_PRIORITY_GROUP_BANDWIDTH - for (i = 0; i < 8; i++) { - TEST_PRIORITY_VALID (bandwidth, i, i, GROUP, TRUE); - TEST_PRIORITY_VALID (bandwidth, i, 7 - i, GROUP, TRUE); - } - - SET_VALID_PRIORITY_GROUP_BANDWIDTH - for (i = 0; i < 8; i++) - TEST_PRIORITY_VALID (strict_bandwidth, i, TRUE, GROUP, TRUE); - - SET_VALID_PRIORITY_GROUP_BANDWIDTH - for (i = 0; i < 8; i++) { - TEST_PRIORITY_VALID (traffic_class, i, i, GROUP, TRUE); - TEST_PRIORITY_VALID (traffic_class, i, 7 - i, GROUP, TRUE); - } -} - -static void -test_dcb_bandwidth_sums (void) -{ - gs_unref_object NMSettingDcb *s_dcb = NULL; - GError *error = NULL; - gboolean success; - - s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); - g_assert (s_dcb); - - /* Assert that setting the value gets the same value back out */ - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 0, 9); - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 1, 10); - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 2, 11); - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 3, 12); - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 4, 13); - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 5, 14); - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 6, 15); - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16); - - /* Assert verify success when sums total 100% */ - g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL); - success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); - g_assert_no_error (error); - g_assert (success); - - /* Assert verify fails when sums do not total 100% */ - nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 4, 20); - success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); - g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); - g_assert (success == FALSE); - g_clear_error (&error); -} - -#define TPATH "/libnm/settings/dcb/" - -NMTST_DEFINE (); - -int -main (int argc, char **argv) -{ - nmtst_init (&argc, &argv, TRUE); - - g_test_add_func (TPATH "flags-valid", test_dcb_flags_valid); - g_test_add_func (TPATH "flags-invalid", test_dcb_flags_invalid); - g_test_add_func (TPATH "app-priorities", test_dcb_app_priorities); - g_test_add_func (TPATH "priorities", test_dcb_priorities_valid); - g_test_add_func (TPATH "bandwidth-sums", test_dcb_bandwidth_sums); - - return g_test_run (); -} - diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c new file mode 100644 index 0000000000..95b2a46f60 --- /dev/null +++ b/libnm-core/tests/test-setting.c @@ -0,0 +1,899 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2008 - 2017 Red Hat, Inc. + * + */ + +#include "nm-default.h" + +#include + +#include "nm-utils.h" +#include "nm-setting-8021x.h" +#include "nm-setting-bond.h" +#include "nm-setting-dcb.h" +#include "nm-connection.h" +#include "nm-simple-connection.h" +#include "nm-setting-connection.h" +#include "nm-errors.h" + +#include "nm-utils/nm-test-utils.h" + +/*****************************************************************************/ + +static void +compare_blob_data (const char *test, + const char *key_path, + GBytes *key) +{ + char *contents = NULL; + gsize len = 0; + GError *error = NULL; + gboolean success; + + g_assert (key && g_bytes_get_size (key) > 0); + + success = g_file_get_contents (key_path, &contents, &len, &error); + nmtst_assert_success (success, error); + + g_assert_cmpmem (contents, len, g_bytes_get_data (key, NULL), g_bytes_get_size (key)); + + g_free (contents); +} + +static void +check_scheme_path (GBytes *value, const char *path) +{ + const guint8 *p; + + g_assert (value); + + p = g_bytes_get_data (value, NULL); + g_assert (memcmp (p, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)) == 0); + p += strlen (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH); + g_assert (memcmp (p, path, strlen (path)) == 0); + p += strlen (path); + g_assert (*p == '\0'); +} + +static void +test_private_key_import (const char *path, + const char *password, + NMSetting8021xCKScheme scheme) +{ + NMSetting8021x *s_8021x; + gboolean success; + NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + NMSetting8021xCKFormat tmp_fmt; + GError *error = NULL; + GBytes *tmp_key = NULL, *client_cert = NULL; + const char *pw; + + s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); + g_assert (s_8021x); + + success = nm_setting_802_1x_set_private_key (s_8021x, + path, + password, + scheme, + &format, + &error); + nmtst_assert_success (success, error); + g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); + tmp_fmt = nm_setting_802_1x_get_private_key_format (s_8021x); + g_assert (tmp_fmt == format); + + /* Make sure the password is what we expect */ + pw = nm_setting_802_1x_get_private_key_password (s_8021x); + g_assert (pw != NULL); + g_assert_cmpstr (pw, ==, password); + + if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { + tmp_key = nm_setting_802_1x_get_private_key_blob (s_8021x); + compare_blob_data ("private-key-import", path, tmp_key); + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { + g_object_get (s_8021x, NM_SETTING_802_1X_PRIVATE_KEY, &tmp_key, NULL); + check_scheme_path (tmp_key, path); + g_bytes_unref (tmp_key); + } else + g_assert_not_reached (); + + /* If it's PKCS#12 ensure the client cert is the same value */ + if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) { + g_object_get (s_8021x, NM_SETTING_802_1X_PRIVATE_KEY, &tmp_key, NULL); + g_assert (tmp_key); + + g_object_get (s_8021x, NM_SETTING_802_1X_CLIENT_CERT, &client_cert, NULL); + g_assert (client_cert); + + /* make sure they are the same */ + g_assert (g_bytes_equal (tmp_key, client_cert)); + + g_bytes_unref (tmp_key); + g_bytes_unref (client_cert); + } + + g_object_unref (s_8021x); +} + +static void +test_phase2_private_key_import (const char *path, + const char *password, + NMSetting8021xCKScheme scheme) +{ + NMSetting8021x *s_8021x; + gboolean success; + NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + NMSetting8021xCKFormat tmp_fmt; + GError *error = NULL; + GBytes *tmp_key = NULL, *client_cert = NULL; + const char *pw; + + s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); + g_assert (s_8021x); + + success = nm_setting_802_1x_set_phase2_private_key (s_8021x, + path, + password, + scheme, + &format, + &error); + nmtst_assert_success (success, error); + g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); + tmp_fmt = nm_setting_802_1x_get_phase2_private_key_format (s_8021x); + g_assert (tmp_fmt == format); + + /* Make sure the password is what we expect */ + pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x); + g_assert (pw); + g_assert_cmpstr (pw, ==, password); + + if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { + tmp_key = nm_setting_802_1x_get_phase2_private_key_blob (s_8021x); + compare_blob_data ("phase2-private-key-import", path, tmp_key); + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { + g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &tmp_key, NULL); + check_scheme_path (tmp_key, path); + g_bytes_unref (tmp_key); + } else + g_assert_not_reached (); + + /* If it's PKCS#12 ensure the client cert is the same value */ + if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) { + g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &tmp_key, NULL); + g_assert (tmp_key); + + g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, &client_cert, NULL); + g_assert (client_cert); + + /* make sure they are the same */ + g_assert (g_bytes_equal (tmp_key, client_cert)); + + g_bytes_unref (tmp_key); + g_bytes_unref (client_cert); + } + + g_object_unref (s_8021x); +} + +static void +test_wrong_password_keeps_data (const char *path, const char *password) +{ + NMSetting8021x *s_8021x; + gboolean success; + NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + GError *error = NULL; + const char *pw; + + s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); + g_assert (s_8021x); + + success = nm_setting_802_1x_set_private_key (s_8021x, + path, + password, + NM_SETTING_802_1X_CK_SCHEME_BLOB, + &format, + &error); + nmtst_assert_success (success, error); + g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); + + /* Now try to set it to something that's not a certificate */ + format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + success = nm_setting_802_1x_set_private_key (s_8021x, + "Makefile.am", + password, + NM_SETTING_802_1X_CK_SCHEME_BLOB, + &format, + &error); + nmtst_assert_no_success (success, error); + g_assert (format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); + g_clear_error (&error); + + /* Make sure the password hasn't changed */ + pw = nm_setting_802_1x_get_private_key_password (s_8021x); + g_assert (pw); + g_assert_cmpstr (pw, ==, password); + + g_object_unref (s_8021x); +} + +static void +test_clear_private_key (const char *path, const char *password) +{ + NMSetting8021x *s_8021x; + gboolean success; + NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + GError *error = NULL; + const char *pw; + + s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); + g_assert (s_8021x); + + success = nm_setting_802_1x_set_private_key (s_8021x, + path, + password, + NM_SETTING_802_1X_CK_SCHEME_BLOB, + &format, + &error); + nmtst_assert_success (success, error); + g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); + + /* Make sure the password is what we expect */ + pw = nm_setting_802_1x_get_private_key_password (s_8021x); + g_assert (pw); + g_assert_cmpstr (pw, ==, password); + + /* Now clear it */ + success = nm_setting_802_1x_set_private_key (s_8021x, + NULL, + NULL, + NM_SETTING_802_1X_CK_SCHEME_BLOB, + NULL, + &error); + nmtst_assert_success (success, error); + + /* Ensure the password is also now clear */ + g_assert (!nm_setting_802_1x_get_private_key_password (s_8021x)); + + g_object_unref (s_8021x); +} + +static void +test_wrong_phase2_password_keeps_data (const char *path, const char *password) +{ + NMSetting8021x *s_8021x; + gboolean success; + NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + GError *error = NULL; + const char *pw; + + s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); + g_assert (s_8021x); + + success = nm_setting_802_1x_set_phase2_private_key (s_8021x, + path, + password, + NM_SETTING_802_1X_CK_SCHEME_BLOB, + &format, + &error); + nmtst_assert_success (success, error); + g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); + + /* Now try to set it to something that's not a certificate */ + format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + success = nm_setting_802_1x_set_phase2_private_key (s_8021x, + "Makefile.am", + password, + NM_SETTING_802_1X_CK_SCHEME_BLOB, + &format, + &error); + nmtst_assert_no_success (success, error); + g_assert (format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); + g_clear_error (&error); + + /* Make sure the password hasn't changed */ + pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x); + g_assert (pw); + g_assert_cmpstr (pw, ==, password); + + g_object_unref (s_8021x); +} + +static void +test_clear_phase2_private_key (const char *path, const char *password) +{ + NMSetting8021x *s_8021x; + gboolean success; + NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + GError *error = NULL; + const char *pw; + + s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); + g_assert (s_8021x); + + success = nm_setting_802_1x_set_phase2_private_key (s_8021x, + path, + password, + NM_SETTING_802_1X_CK_SCHEME_BLOB, + &format, + &error); + nmtst_assert_success (success, error); + g_assert (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN); + + /* Make sure the password is what we expect */ + pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x); + g_assert (pw); + g_assert_cmpstr (pw, ==, password); + + /* Now clear it */ + success = nm_setting_802_1x_set_phase2_private_key (s_8021x, + NULL, + NULL, + NM_SETTING_802_1X_CK_SCHEME_BLOB, + NULL, + &error); + nmtst_assert_success (success, error); + + /* Ensure the password is also now clear */ + g_assert (!nm_setting_802_1x_get_phase2_private_key_password (s_8021x)); + + g_object_unref (s_8021x); +} + +static void +test_8021x (gconstpointer test_data) +{ + char **parts, *path, *password; + + parts = g_strsplit ((const char *) test_data, ", ", -1); + g_assert_cmpint (g_strv_length (parts), ==, 2); + + path = g_build_filename (TEST_CERT_DIR, parts[0], NULL); + password = parts[1]; + + /* Test phase1 and phase2 path scheme */ + test_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_PATH); + test_phase2_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_PATH); + + /* Test phase1 and phase2 blob scheme */ + test_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_BLOB); + test_phase2_private_key_import (path, password, NM_SETTING_802_1X_CK_SCHEME_BLOB); + + /* Test that using a wrong password does not change existing data */ + test_wrong_password_keeps_data (path, password); + test_wrong_phase2_password_keeps_data (path, password); + + /* Test clearing the private key */ + test_clear_private_key (path, password); + test_clear_phase2_private_key (path, password); + + g_free (path); + g_strfreev (parts); +} + +/*****************************************************************************/ + +static void +create_bond_connection (NMConnection **con, NMSettingBond **s_bond) +{ + NMSettingConnection *s_con; + + g_assert (con); + g_assert (s_bond); + + *con = nmtst_create_minimal_connection ("bond", + NULL, + NM_SETTING_BOND_SETTING_NAME, + &s_con); + g_assert (*con); + g_assert (s_con); + + g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, "bond0", NULL); + + *s_bond = (NMSettingBond *) nm_setting_bond_new (); + g_assert (*s_bond); + + nm_connection_add_setting (*con, NM_SETTING (*s_bond)); +} + +#define test_verify_options(exp, ...) \ + G_STMT_START { \ + const char *__opts[] = { __VA_ARGS__ , NULL }; \ + \ + _test_verify_options (__opts, exp); \ + } G_STMT_END + +static void +_test_verify_options (const char **options, gboolean expected_result) +{ + gs_unref_object NMConnection *con = NULL; + NMSettingBond *s_bond; + GError *error = NULL; + gboolean success; + const char **option; + + create_bond_connection (&con, &s_bond); + + for (option = options; option[0] && option[1]; option += 2) + g_assert (nm_setting_bond_add_option (s_bond, option[0], option[1])); + + if (expected_result) { + nmtst_assert_connection_verifies_and_normalizable (con); + nmtst_connection_normalize (con); + success = nm_setting_verify ((NMSetting *) s_bond, con, &error); + nmtst_assert_success (success, error); + } else { + nmtst_assert_connection_unnormalizable (con, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY); + } +} + +static void +test_bond_verify (void) +{ + test_verify_options (TRUE, + "mode", "3", + "arp_interval", "0"); + test_verify_options (FALSE, + /* arp_interval not supported in balance-alb mode */ + "mode", "balance-alb", + "arp_interval", "1", + "arp_ip_target", "1.2.3.4"); + test_verify_options (FALSE, + /* arp_ip_target requires arp_interval */ + "mode", "balance-rr", + "arp_ip_target", "1.2.3.4"); + test_verify_options (TRUE, + "mode", "balance-rr", + "arp_interval", "1", + "arp_ip_target", "1.2.3.4"); + test_verify_options (FALSE, + /* num_grat_arp, num_unsol_na cannot be different */ + "mode", "balance-rr", + "num_grat_arp", "3", + "num_unsol_na", "4"); + test_verify_options (TRUE, + "mode", "balance-rr", + "num_grat_arp", "5", + "num_unsol_na", "5"); + test_verify_options (TRUE, + "mode", "active-backup", + "primary", "eth0"); + test_verify_options (FALSE, + /* primary requires mode=active-backup */ + "mode", "802.3ad", + "primary", "eth0"); + test_verify_options (TRUE, + "mode", "802.3ad", + "lacp_rate", "fast"); + test_verify_options (FALSE, + /* lacp_rate=fast requires mode=802.3ad */ + "mode", "balance-rr", + "lacp_rate", "fast"); + test_verify_options (TRUE, + "mode", "802.3ad", + "ad_actor_system", "ae:00:11:33:44:55"); +} + +static void +test_bond_compare_options (gboolean exp_res, const char **opts1, const char **opts2) +{ + gs_unref_object NMSettingBond *s_bond1 = NULL, *s_bond2 = NULL; + const char **p; + + s_bond1 = (NMSettingBond *) nm_setting_bond_new (); + g_assert (s_bond1); + s_bond2 = (NMSettingBond *) nm_setting_bond_new (); + g_assert (s_bond2); + + for (p = opts1; p[0] && p[1]; p += 2) + g_assert (nm_setting_bond_add_option (s_bond1, p[0], p[1])); + + for (p = opts2; p[0] && p[1]; p += 2) + g_assert (nm_setting_bond_add_option (s_bond2, p[0], p[1])); + + g_assert_cmpint (nm_setting_compare ((NMSetting *) s_bond1, + (NMSetting *) s_bond2, + NM_SETTING_COMPARE_FLAG_EXACT), + ==, + exp_res); +} + +static void +test_bond_compare (void) +{ + test_bond_compare_options (TRUE, + ((const char *[]){ "mode", "balance-rr", "miimon", "1", NULL }), + ((const char *[]){ "mode", "balance-rr", "miimon", "1", NULL })); + test_bond_compare_options (FALSE, + ((const char *[]){ "mode", "balance-rr", "miimon", "1", NULL }), + ((const char *[]){ "mode", "balance-rr", "miimon", "2", NULL })); + + /* ignore default values */ + test_bond_compare_options (TRUE, + ((const char *[]){ "miimon", "1", NULL }), + ((const char *[]){ "miimon", "1", "updelay", "0", NULL })); + + /* special handling of num_grat_arp, num_unsol_na */ + test_bond_compare_options (FALSE, + ((const char *[]){ "num_grat_arp", "2", NULL }), + ((const char *[]){ "num_grat_arp", "1", NULL })); + test_bond_compare_options (TRUE, + ((const char *[]){ "num_grat_arp", "3", NULL }), + ((const char *[]){ "num_unsol_na", "3", NULL })); + test_bond_compare_options (TRUE, + ((const char *[]){ "num_grat_arp", "4", NULL }), + ((const char *[]){ "num_unsol_na", "4", "num_grat_arp", "4", NULL })); +} + +static void +test_bond_normalize_options (const char **opts1, const char **opts2) +{ + gs_unref_object NMConnection *con = NULL; + NMSettingBond *s_bond; + GError *error = NULL; + gboolean success; + const char **p; + int num = 0; + + create_bond_connection (&con, &s_bond); + + for (p = opts1; p[0] && p[1]; p += 2) + g_assert (nm_setting_bond_add_option (s_bond, p[0], p[1])); + + nmtst_assert_connection_verifies_and_normalizable (con); + nmtst_connection_normalize (con); + success = nm_setting_verify ((NMSetting *) s_bond, con, &error); + nmtst_assert_success (success, error); + + for (p = opts2; p[0] && p[1]; p += 2) { + g_assert_cmpstr (nm_setting_bond_get_option_by_name (s_bond, p[0]), ==, p[1]); + num++; + } + + g_assert_cmpint (num, ==, nm_setting_bond_get_num_options (s_bond)); +} + +static void +test_bond_normalize (void) +{ + test_bond_normalize_options ( + ((const char *[]){ "mode", "802.3ad", "ad_actor_system", "00:02:03:04:05:06", NULL }), + ((const char *[]){ "mode", "802.3ad", "ad_actor_system", "00:02:03:04:05:06", NULL })); + test_bond_normalize_options ( + ((const char *[]){ "mode", "1", "miimon", "1", NULL }), + ((const char *[]){ "mode", "active-backup", "miimon", "1", NULL })); + test_bond_normalize_options ( + ((const char *[]){ "mode", "balance-alb", "tlb_dynamic_lb", "1", NULL }), + ((const char *[]){ "mode", "balance-alb", NULL })); + test_bond_normalize_options ( + ((const char *[]){ "mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL }), + ((const char *[]){ "mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL })); + test_bond_normalize_options ( + ((const char *[]){ "mode", "balance-rr", "ad_actor_sys_prio", "4", "packets_per_slave", "3", NULL }), + ((const char *[]){ "mode", "balance-rr", "packets_per_slave", "3", NULL })); +} + +/*****************************************************************************/ + +#define DCB_FLAGS_ALL (NM_SETTING_DCB_FLAG_ENABLE | \ + NM_SETTING_DCB_FLAG_ADVERTISE | \ + NM_SETTING_DCB_FLAG_WILLING) + + +static void +test_dcb_flags_valid (void) +{ + gs_unref_object NMSettingDcb *s_dcb = NULL; + GError *error = NULL; + gboolean success; + guint i; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, 0); + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, 0); + g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, 0); + g_assert_cmpint (nm_setting_dcb_get_priority_flow_control_flags (s_dcb), ==, 0); + g_assert_cmpint (nm_setting_dcb_get_priority_group_flags (s_dcb), ==, 0); + + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_APP_FCOE_FLAGS, DCB_FLAGS_ALL, + NM_SETTING_DCB_APP_ISCSI_FLAGS, DCB_FLAGS_ALL, + NM_SETTING_DCB_APP_FIP_FLAGS, DCB_FLAGS_ALL, + NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, DCB_FLAGS_ALL, + NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, DCB_FLAGS_ALL, + NULL); + /* Priority Group Bandwidth must total 100% */ + for (i = 0; i < 7; i++) + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, i, 12); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16); + + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); + g_assert_no_error (error); + g_assert (success); + + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, DCB_FLAGS_ALL); + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, DCB_FLAGS_ALL); + g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, DCB_FLAGS_ALL); + g_assert_cmpint (nm_setting_dcb_get_priority_flow_control_flags (s_dcb), ==, DCB_FLAGS_ALL); + g_assert_cmpint (nm_setting_dcb_get_priority_group_flags (s_dcb), ==, DCB_FLAGS_ALL); +} + +#define TEST_FLAG(p, f, v) \ +{ \ + /* GObject property min/max should ensure the property does not get set to \ + * the invalid value, so we ensure the value we just tried to set is 0 and \ + * that verify is successful since the property never got set. \ + */ \ + g_object_set (G_OBJECT (s_dcb), p, v, NULL); \ + g_assert_cmpint (f (s_dcb), ==, 0); \ + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ + g_assert_no_error (error); \ + g_assert (success); \ +} + +static void +test_dcb_flags_invalid (void) +{ + gs_unref_object NMSettingDcb *s_dcb = NULL; + GError *error = NULL; + gboolean success; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*"); + TEST_FLAG (NM_SETTING_DCB_APP_FCOE_FLAGS, nm_setting_dcb_get_app_fcoe_flags, 0x332523); + g_test_assert_expected_messages (); + + g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*"); + TEST_FLAG (NM_SETTING_DCB_APP_ISCSI_FLAGS, nm_setting_dcb_get_app_iscsi_flags, 0xFF); + g_test_assert_expected_messages (); + + g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*"); + TEST_FLAG (NM_SETTING_DCB_APP_FIP_FLAGS, nm_setting_dcb_get_app_fip_flags, 0x1111); + g_test_assert_expected_messages (); + + g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*"); + TEST_FLAG (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, nm_setting_dcb_get_priority_flow_control_flags, G_MAXUINT32); + g_test_assert_expected_messages (); + + g_test_expect_message ("GLib-GObject", G_LOG_LEVEL_WARNING, "*invalid or out of range*"); + TEST_FLAG (NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, nm_setting_dcb_get_priority_group_flags, + (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE | NM_SETTING_DCB_FLAG_WILLING) + 1); + g_test_assert_expected_messages (); +} + +#define TEST_APP_PRIORITY(lcprop, ucprop, v) \ +{ \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_FLAGS, NM_SETTING_DCB_FLAG_NONE, NULL); \ + \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_PRIORITY, v, NULL); \ + g_assert_cmpint (nm_setting_dcb_get_app_##lcprop##_priority (s_dcb), ==, v); \ + \ + /* Assert that the setting is invalid while the app is disabled unless v is default */ \ + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ + if (v >= 0) { \ + g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); \ + g_assert (success == FALSE); \ + } else { \ + g_assert_no_error (error); \ + g_assert (success); \ + } \ + g_clear_error (&error); \ + \ + /* Set the enable flag and re-verify, this time it should be valid */ \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL); \ + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ + g_assert_no_error (error); \ + g_assert (success); \ + \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_PRIORITY, 0, NULL); \ +} + +static void +test_dcb_app_priorities (void) +{ + gs_unref_object NMSettingDcb *s_dcb = NULL; + GError *error = NULL; + gboolean success; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + /* Defaults */ + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_priority (s_dcb), ==, -1); + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_priority (s_dcb), ==, -1); + g_assert_cmpint (nm_setting_dcb_get_app_fip_priority (s_dcb), ==, -1); + + TEST_APP_PRIORITY (fcoe, FCOE, 6); + TEST_APP_PRIORITY (iscsi, ISCSI, 5); + TEST_APP_PRIORITY (fip, FIP, 4); + + TEST_APP_PRIORITY (fcoe, FCOE, -1); + TEST_APP_PRIORITY (iscsi, ISCSI, -1); + TEST_APP_PRIORITY (fip, FIP, -1); +} + +#define TEST_PRIORITY_VALID(fn, id, val, flagsprop, verify) \ +{ \ + /* Assert that setting the value gets the same value back out */ \ + nm_setting_dcb_set_priority_##fn (s_dcb, id, val); \ + g_assert_cmpint (nm_setting_dcb_get_priority_##fn (s_dcb, id), ==, val); \ + \ + if (verify) { \ + if (val != 0) { \ + /* Assert that verify fails because the flags do not include 'enabled' \ + * and a value has been set. \ + */ \ + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ + g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); \ + g_assert (success == FALSE); \ + g_clear_error (&error); \ + } \ + \ + /* Assert that adding the 'enabled' flag verifies the setting */ \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_##flagsprop##_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL); \ + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ + g_assert_no_error (error); \ + g_assert (success); \ + } \ + \ + /* Reset everything */ \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_##flagsprop##_FLAGS, NM_SETTING_DCB_FLAG_NONE, NULL); \ + nm_setting_dcb_set_priority_##fn (s_dcb, id, 0); \ +} + +/* If Priority Groups are enabled, PG bandwidth must equal 100% */ +#define SET_VALID_PRIORITY_GROUP_BANDWIDTH \ +{ \ + guint x; \ + for (x = 0; x < 7; x++) \ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, x, 12); \ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16); \ +} + +static void +test_dcb_priorities_valid (void) +{ + gs_unref_object NMSettingDcb *s_dcb = NULL; + GError *error = NULL; + gboolean success; + guint i; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + for (i = 0; i < 8; i++) + TEST_PRIORITY_VALID (flow_control, i, TRUE, FLOW_CONTROL, TRUE); + + SET_VALID_PRIORITY_GROUP_BANDWIDTH + for (i = 0; i < 8; i++) { + TEST_PRIORITY_VALID (group_id, i, i, GROUP, TRUE); + TEST_PRIORITY_VALID (group_id, i, 7 - i, GROUP, TRUE); + } + + /* Clear PG bandwidth from earlier tests */ + for (i = 0; i < 8; i++) + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, i, 0); + + /* Priority Group Bandwidth must add up to 100% if enabled, which requires + * some dancing for verifying individual values here. + */ + for (i = 0; i < 8; i++) { + guint other = 7 - (i % 8); + + /* Set another priority group to the remaining bandwidth */ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 100 - i); + TEST_PRIORITY_VALID (group_bandwidth, i, i, GROUP, TRUE); + + /* Set another priority group to the remaining bandwidth */ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 100 - (7 - i)); + TEST_PRIORITY_VALID (group_bandwidth, i, 7 - i, GROUP, TRUE); + + /* Clear remaining bandwidth */ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 0); + } + + SET_VALID_PRIORITY_GROUP_BANDWIDTH + for (i = 0; i < 8; i++) { + TEST_PRIORITY_VALID (bandwidth, i, i, GROUP, TRUE); + TEST_PRIORITY_VALID (bandwidth, i, 7 - i, GROUP, TRUE); + } + + SET_VALID_PRIORITY_GROUP_BANDWIDTH + for (i = 0; i < 8; i++) + TEST_PRIORITY_VALID (strict_bandwidth, i, TRUE, GROUP, TRUE); + + SET_VALID_PRIORITY_GROUP_BANDWIDTH + for (i = 0; i < 8; i++) { + TEST_PRIORITY_VALID (traffic_class, i, i, GROUP, TRUE); + TEST_PRIORITY_VALID (traffic_class, i, 7 - i, GROUP, TRUE); + } +} + +static void +test_dcb_bandwidth_sums (void) +{ + gs_unref_object NMSettingDcb *s_dcb = NULL; + GError *error = NULL; + gboolean success; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + /* Assert that setting the value gets the same value back out */ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 0, 9); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 1, 10); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 2, 11); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 3, 12); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 4, 13); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 5, 14); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 6, 15); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16); + + /* Assert verify success when sums total 100% */ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL); + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); + g_assert_no_error (error); + g_assert (success); + + /* Assert verify fails when sums do not total 100% */ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 4, 20); + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); + g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); + g_assert (success == FALSE); + g_clear_error (&error); +} + +/*****************************************************************************/ + + +NMTST_DEFINE (); + +int +main (int argc, char **argv) +{ + nmtst_init (&argc, &argv, TRUE); + + g_test_add_data_func ("/libnm/setting-8021x/key-and-cert", + "test_key_and_cert.pem, test", + test_8021x); + g_test_add_data_func ("/libnm/setting-8021x/key-only", + "test-key-only.pem, test", + test_8021x); + g_test_add_data_func ("/libnm/setting-8021x/pkcs8-enc-key", + "pkcs8-enc-key.pem, 1234567890", + test_8021x); + g_test_add_data_func ("/libnm/setting-8021x/pkcs12", + "test-cert.p12, test", + test_8021x); + + g_test_add_func ("/libnm/settings/bond/verify", test_bond_verify); + g_test_add_func ("/libnm/settings/bond/compare", test_bond_compare); + g_test_add_func ("/libnm/settings/bond/normalize", test_bond_normalize); + + g_test_add_func ("/libnm/settings/dcb/flags-valid", test_dcb_flags_valid); + g_test_add_func ("/libnm/settings/dcb/flags-invalid", test_dcb_flags_invalid); + g_test_add_func ("/libnm/settings/dcb/app-priorities", test_dcb_app_priorities); + g_test_add_func ("/libnm/settings/dcb/priorities", test_dcb_priorities_valid); + g_test_add_func ("/libnm/settings/dcb/bandwidth-sums", test_dcb_bandwidth_sums); + + return g_test_run (); +} From ace038539afe3510d36b9525dd25d1301772dd05 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Wed, 6 Dec 2017 19:26:09 +0100 Subject: [PATCH 21/23] gitignore: ignore libnm-core/tests/test-setting We now have merged in libnm-core/tests/test-setting test file the test files for 8021x, bond and dcb... add the new test file to .gitignore and remove the old ones. (cherry picked from commit 540b7b3dfdf71d1833f72870b526e686db29abb6) --- .gitignore | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index cd4fca45a9..2b8da0acac 100644 --- a/.gitignore +++ b/.gitignore @@ -155,9 +155,7 @@ test-*.trs /libnm-core/tests/test-keyfile /libnm-core/tests/test-need-secrets /libnm-core/tests/test-secrets -/libnm-core/tests/test-setting-8021x -/libnm-core/tests/test-setting-bond -/libnm-core/tests/test-setting-dcb +/libnm-core/tests/test-setting /libnm-core/nm-dbus-types.xml /libnm-core/nm-vpn-dbus-types.xml From 7abcede5bb6ffedd85d92795c4e67c0a5e6f257c Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Wed, 22 Nov 2017 14:44:43 +0100 Subject: [PATCH 22/23] libnm-core: add test cases for NMSettingTeam (cherry picked from commit 1248969342ffc085b09e356b6f03af7e35ce62c0) --- libnm-core/tests/test-setting.c | 281 ++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index 95b2a46f60..47f7affe6d 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -25,6 +25,7 @@ #include "nm-setting-8021x.h" #include "nm-setting-bond.h" #include "nm-setting-dcb.h" +#include "nm-setting-team.h" #include "nm-connection.h" #include "nm-simple-connection.h" #include "nm-setting-connection.h" @@ -864,6 +865,265 @@ test_dcb_bandwidth_sums (void) /*****************************************************************************/ +static void +_test_team_config_sync (const char *team_config, + int notify_peer_count, + int notify_peers_interval, + int mcast_rejoin_count, + int mcast_rejoin_interval, + char *runner, + char *runner_hwaddr_policy, /* activebackup */ + GPtrArray *runner_tx_hash, /* lacp, loadbalance */ + char *runner_tx_balancer, /* lacp, loadbalance */ + int runner_tx_balancer_interval, /* lacp, loadbalance */ + gboolean runner_active, /* lacp */ + gboolean runner_fast_rate, /* lacp */ + int runner_sys_prio, /* lacp */ + int runner_min_ports, /* lacp */ + char *runner_agg_select_policy, /* lacp */ + GPtrArray *link_watchers) +{ + gs_unref_object NMSettingTeam *s_team = NULL; + guint i, j; + gboolean found; + + s_team = (NMSettingTeam *) nm_setting_team_new (); + g_assert (s_team); + + g_object_set (s_team, NM_SETTING_TEAM_CONFIG, team_config, NULL); + g_assert (nm_setting_team_get_notify_peers_count (s_team) == notify_peer_count); + g_assert (nm_setting_team_get_notify_peers_interval (s_team) == notify_peers_interval); + g_assert (nm_setting_team_get_mcast_rejoin_count (s_team) == mcast_rejoin_count); + g_assert (nm_setting_team_get_mcast_rejoin_interval (s_team) == mcast_rejoin_interval); + g_assert (nm_setting_team_get_runner_tx_balancer_interval (s_team) == runner_tx_balancer_interval); + g_assert (nm_setting_team_get_runner_active (s_team) == runner_active); + g_assert (nm_setting_team_get_runner_fast_rate (s_team) == runner_fast_rate); + g_assert (nm_setting_team_get_runner_sys_prio (s_team) == runner_sys_prio); + g_assert (nm_setting_team_get_runner_min_ports (s_team) == runner_min_ports); + g_assert (nm_streq0 (nm_setting_team_get_runner (s_team), runner)); + g_assert (nm_streq0 (nm_setting_team_get_runner_hwaddr_policy (s_team), runner_hwaddr_policy)); + g_assert (nm_streq0 (nm_setting_team_get_runner_tx_balancer (s_team), runner_tx_balancer)); + g_assert (nm_streq0 (nm_setting_team_get_runner_agg_select_policy (s_team), runner_agg_select_policy)); + + if (runner_tx_hash) { + g_assert (runner_tx_hash->len == nm_setting_team_get_num_runner_tx_hash (s_team)); + for (i = 0; i < runner_tx_hash->len; i++) { + found = FALSE; + for (j = 0; j < nm_setting_team_get_num_runner_tx_hash (s_team); j++) { + if (nm_streq0 (nm_setting_team_get_runner_tx_hash (s_team, j), + runner_tx_hash->pdata[i])) { + found = TRUE; + break; + } + } + g_assert (found); + } + } + + if (link_watchers) { + g_assert (link_watchers->len == nm_setting_team_get_num_link_watchers (s_team)); + for (i = 0; i < link_watchers->len; i++) { + found = FALSE; + for (j = 0; j < nm_setting_team_get_num_link_watchers (s_team); j++) { + if (nm_team_link_watcher_equal (link_watchers->pdata[i], + nm_setting_team_get_link_watcher (s_team, j))) { + found = TRUE; + break; + } + } + g_assert (found); + } + } + + g_assert (nm_setting_verify ((NMSetting *) s_team, NULL, NULL)); +} + + +static void +test_runner_roundrobin_sync_from_config (void) +{ + _test_team_config_sync ("", + 0, 0, 0, 0, + NM_SETTING_TEAM_RUNNER_ROUNDROBIN, + NULL, + NULL, NULL, -1, + FALSE, FALSE, -1, -1, NULL, + NULL); +} + +static void +test_runner_broadcast_sync_from_config (void) +{ + _test_team_config_sync ("{\"runner\": {\"name\": \"broadcast\"}}", + 0, 0, 0, 0, + NM_SETTING_TEAM_RUNNER_BROADCAST, + NULL, + NULL, NULL, -1, + FALSE, FALSE, -1, -1, NULL, + NULL); +} + +static void +test_runner_activebackup_sync_from_config (void) +{ + _test_team_config_sync ("{\"runner\": {\"name\": \"activebackup\"}}", + NM_SETTING_TEAM_NOTIFY_PEERS_COUNT_ACTIVEBACKUP_DEFAULT, 0, + NM_SETTING_TEAM_NOTIFY_MCAST_COUNT_ACTIVEBACKUP_DEFAULT, 0, + NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP, + NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_DEFAULT, + NULL, NULL, -1, + FALSE, FALSE, -1, -1, NULL, + NULL); +} + +static void +test_runner_loadbalance_sync_from_config (void) +{ + gs_unref_ptrarray GPtrArray *tx_hash = NULL; + + tx_hash = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); + g_ptr_array_add (tx_hash, g_strdup ("eth")); + g_ptr_array_add (tx_hash, g_strdup ("ipv4")); + g_ptr_array_add (tx_hash, g_strdup ("ipv6")); + + _test_team_config_sync ("{\"runner\": {\"name\": \"loadbalance\"}}", + 0, 0, 0, 0, + NM_SETTING_TEAM_RUNNER_LOADBALANCE, + NULL, + tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT, + FALSE, FALSE, -1, -1, NULL, + NULL); + + _test_team_config_sync ("{\"runner\": {\"name\": \"loadbalance\", " + "\"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"]}}", + 0, 0, 0, 0, + NM_SETTING_TEAM_RUNNER_LOADBALANCE, + NULL, + tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT, + FALSE, FALSE, -1, -1, NULL, + NULL); + + _test_team_config_sync ("{\"runner\": {\"name\": \"loadbalance\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"], " + "\"tx_balancer\": {\"name\": \"basic\", \"balancing_interval\": 30}}}", + 0, 0, 0, 0, + NM_SETTING_TEAM_RUNNER_LOADBALANCE, + NULL, + tx_hash, "basic", 30, + FALSE, FALSE, -1, -1, NULL, + NULL); +} + +static void +test_runner_lacp_sync_from_config (void) +{ + gs_unref_ptrarray GPtrArray *tx_hash = NULL; + + tx_hash = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); + g_ptr_array_add (tx_hash, g_strdup ("eth")); + g_ptr_array_add (tx_hash, g_strdup ("ipv4")); + g_ptr_array_add (tx_hash, g_strdup ("ipv6")); + + _test_team_config_sync ("{\"runner\": {\"name\": \"lacp\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"]}}", + 0, 0, 0, 0, + NM_SETTING_TEAM_RUNNER_LACP, + NULL, + tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT, + TRUE, FALSE, NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT, 0, + NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY_DEFAULT, + NULL); + + _test_team_config_sync ("{\"runner\": {\"name\": \"lacp\", \"tx_hash\": [\"eth\", \"ipv4\", \"ipv6\"], " + "\"active\": false, \"fast_rate\": true, \"sys_prio\": 10, \"min_ports\": 5, " + "\"agg_select_policy\": \"port_config\"}}", + 0, 0, 0, 0, + NM_SETTING_TEAM_RUNNER_LACP, + NULL, + tx_hash, NULL, NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT, + FALSE, TRUE, 10, 5, "port_config", + NULL); +} + +static void +test_watcher_ethtool_sync_from_config (void) +{ + gs_unref_ptrarray GPtrArray *link_watchers = NULL; + + link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); + g_ptr_array_add (link_watchers, nm_team_link_watcher_new_ethtool (0, 0, NULL)); + _test_team_config_sync ("{\"link_watch\": {\"name\": \"ethtool\"}}", + 0, 0, 0, 0, + "roundrobin", + NULL, + NULL, NULL, -1, + FALSE, FALSE, -1, -1, NULL, + link_watchers); +} + +static void +test_watcher_nsna_ping_sync_from_config (void) +{ + gs_unref_ptrarray GPtrArray *link_watchers = NULL; + + link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); + g_ptr_array_add (link_watchers, nm_team_link_watcher_new_nsna_ping (0, 0, 3, "target.host", NULL)); + _test_team_config_sync ("{\"link_watch\": {\"name\": \"nsna_ping\", \"target_host\": \"target.host\"}}", + 0, 0, 0, 0, + "roundrobin", + NULL, + NULL, NULL, -1, + FALSE, FALSE, -1, -1, NULL, + link_watchers); +} + +static void +test_watcher_arp_ping_sync_from_config (void) +{ + gs_unref_ptrarray GPtrArray *link_watchers = NULL; + + link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); + g_ptr_array_add (link_watchers, + nm_team_link_watcher_new_arp_ping (0, 0, 3, "target.host", "source.host", 0, NULL)); + _test_team_config_sync ("{\"link_watch\": {\"name\": \"arp_ping\", \"target_host\": \"target.host\", " + "\"source_host\": \"source.host\"}}", + 0, 0, 0, 0, + "roundrobin", + NULL, + NULL, NULL, -1, + FALSE, FALSE, -1, -1, NULL, + link_watchers); +} + +static void +test_multiple_watchers_sync_from_config (void) +{ + gs_unref_ptrarray GPtrArray *link_watchers = NULL; + + link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); + g_ptr_array_add (link_watchers, nm_team_link_watcher_new_ethtool (2, 4, NULL)); + g_ptr_array_add (link_watchers, nm_team_link_watcher_new_nsna_ping (3, 6, 9, "target.host", NULL)); + g_ptr_array_add (link_watchers, + nm_team_link_watcher_new_arp_ping (5, 10, 15, "target.host", "source.host", + NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE + | NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE + | NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS, + NULL)); + _test_team_config_sync ("{\"link_watch\": [" + "{\"name\": \"ethtool\", \"delay_up\": 2, \"delay_down\": 4}, " + "{\"name\": \"arp_ping\", \"init_wait\": 5, \"interval\": 10, \"missed_max\": 15, " + "\"target_host\": \"target.host\", \"source_host\": \"source.host\", " + "\"validate_active\": true, \"validate_inactive\": true, \"send_always\": true}, " + "{\"name\": \"nsna_ping\", \"init_wait\": 3, \"interval\": 6, \"missed_max\": 9, " + "\"target_host\": \"target.host\"}]}", + 0, 0, 0, 0, + "roundrobin", + NULL, + NULL, NULL, -1, + FALSE, FALSE, -1, -1, NULL, + link_watchers); +} + +/*****************************************************************************/ + NMTST_DEFINE (); @@ -895,5 +1155,26 @@ main (int argc, char **argv) g_test_add_func ("/libnm/settings/dcb/priorities", test_dcb_priorities_valid); g_test_add_func ("/libnm/settings/dcb/bandwidth-sums", test_dcb_bandwidth_sums); +#if WITH_JANSSON + g_test_add_func ("/libnm/settings/team/sync_runner_from_config_roundrobin", + test_runner_roundrobin_sync_from_config); + g_test_add_func ("/libnm/settings/team/sync_runner_from_config_broadcast", + test_runner_broadcast_sync_from_config); + g_test_add_func ("/libnm/settings/team/sync_runner_from_config_activebackup", + test_runner_activebackup_sync_from_config); + g_test_add_func ("/libnm/settings/team/sync_runner_from_config_loadbalance", + test_runner_loadbalance_sync_from_config); + g_test_add_func ("/libnm/settings/team/sync_runner_from_config_lacp", + test_runner_lacp_sync_from_config); + g_test_add_func ("/libnm/settings/team/sync_watcher_from_config_ethtool", + test_watcher_ethtool_sync_from_config); + g_test_add_func ("/libnm/settings/team/sync_watcher_from_config_nsna_ping", + test_watcher_nsna_ping_sync_from_config); + g_test_add_func ("/libnm/settings/team/sync_watcher_from_config_arp_ping", + test_watcher_arp_ping_sync_from_config); + g_test_add_func ("/libnm/settings/team/sync_watcher_from_config_all", + test_multiple_watchers_sync_from_config); +#endif + return g_test_run (); } From 78d10c9d18844f2af0dae23d0a1b257d25133389 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Fri, 1 Dec 2017 10:07:04 +0100 Subject: [PATCH 23/23] libnm-core: add test cases for NMSettingTeamPort (cherry picked from commit b5f0d61d03620860d07580e199b0693c7646b53d) --- libnm-core/tests/test-setting.c | 131 ++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index 47f7affe6d..b9f9a6f7ce 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -26,6 +26,7 @@ #include "nm-setting-bond.h" #include "nm-setting-dcb.h" #include "nm-setting-team.h" +#include "nm-setting-team-port.h" #include "nm-connection.h" #include "nm-simple-connection.h" #include "nm-setting-connection.h" @@ -1124,6 +1125,127 @@ test_multiple_watchers_sync_from_config (void) /*****************************************************************************/ +static void +_test_team_port_config_sync (const char *team_port_config, + int queue_id, + int prio, + gboolean sticky, + int lacp_prio, + int lacp_key, + GPtrArray *link_watchers) +{ + NMSettingTeamPort *s_team_port; + guint i, j; + gboolean found; + + s_team_port = (NMSettingTeamPort *) nm_setting_team_port_new (); + g_assert (s_team_port); + + g_object_set (s_team_port, NM_SETTING_TEAM_CONFIG, team_port_config, NULL); + g_assert (nm_setting_team_port_get_queue_id (s_team_port) == queue_id); + g_assert (nm_setting_team_port_get_prio (s_team_port) == prio); + g_assert (nm_setting_team_port_get_sticky (s_team_port) == sticky); + g_assert (nm_setting_team_port_get_lacp_prio (s_team_port) == lacp_prio); + g_assert (nm_setting_team_port_get_lacp_key (s_team_port) == lacp_key); + + if (link_watchers) { + g_assert (link_watchers->len == nm_setting_team_port_get_num_link_watchers (s_team_port)); + for (i = 0; i < link_watchers->len; i++) { + found = FALSE; + for (j = 0; j < nm_setting_team_port_get_num_link_watchers (s_team_port); j++) { + if (nm_team_link_watcher_equal (link_watchers->pdata[i], + nm_setting_team_port_get_link_watcher (s_team_port, + j))) { + found = TRUE; + break; + } + } + g_assert (found); + } + } + + g_assert (nm_setting_verify ((NMSetting *) s_team_port, NULL, NULL)); +} + + +static void +test_team_port_default (void) +{ + _test_team_port_config_sync ("", -1, 0, FALSE, 255, 0, NULL); +} + +static void +test_team_port_queue_id (void) +{ + _test_team_port_config_sync ("{\"queue_id\": 3}", + 3, 0, FALSE, 255, 0, NULL); + _test_team_port_config_sync ("{\"queue_id\": 0}", + 0, 0, FALSE, 255, 0, NULL); +} + +static void +test_team_port_prio (void) +{ + _test_team_port_config_sync ("{\"prio\": 6}", + -1, 6, FALSE, 255, 0, NULL); + _test_team_port_config_sync ("{\"prio\": 0}", + -1, 0, FALSE, 255, 0, NULL); +} + +static void +test_team_port_sticky (void) +{ + _test_team_port_config_sync ("{\"sticky\": true}", + -1, 0, TRUE, 255, 0, NULL); + _test_team_port_config_sync ("{\"sticky\": false}", + -1, 0, FALSE, 255, 0, NULL); +} + +static void +test_team_port_lacp_prio (void) +{ + _test_team_port_config_sync ("{\"lacp_prio\": 9}", + -1, 0, FALSE, 9, 0, NULL); + _test_team_port_config_sync ("{\"lacp_prio\": 0}", + -1, 0, FALSE, 0, 0, NULL); +} + +static void +test_team_port_lacp_key (void) +{ + _test_team_port_config_sync ("{\"lacp_key\": 12}", + -1, 0, FALSE, 255, 12, NULL); + _test_team_port_config_sync ("{\"lacp_key\": 0}", + -1, 0, FALSE, 255, 0, NULL); +} + +static void +test_team_port_full_config (void) +{ + gs_unref_ptrarray GPtrArray *link_watchers = NULL; + + link_watchers = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_team_link_watcher_unref); + g_ptr_array_add (link_watchers, + nm_team_link_watcher_new_arp_ping (0, 3, 3, "1.2.3.2", "1.2.3.1", + NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE, + NULL)); + g_ptr_array_add (link_watchers, + nm_team_link_watcher_new_arp_ping (1, 1, 0, "1.2.3.4", "1.2.3.1", + NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS, + NULL)); + + _test_team_port_config_sync ("{\"queue_id\": 10, \"prio\": 20, \"sticky\": true, \"lacp_prio\": 30, " + "\"lacp_key\": 40, \"link_watch\": [" + "{\"name\": \"arp_ping\", \"interval\": 3, \"target_host\": \"1.2.3.2\", " + "\"source_host\": \"1.2.3.1\", \"validate_inactive\": true}, " + "{\"name\": \"arp_ping\", \"init_wait\": 1, \"interval\": 1, " + "\"target_host\": \"1.2.3.4\", \"source_host\": \"1.2.3.1\", " + "\"send_always\": true}]}", + 10, 20, true, 30, 40, NULL); +} + +/*****************************************************************************/ + NMTST_DEFINE (); @@ -1174,6 +1296,15 @@ main (int argc, char **argv) test_watcher_arp_ping_sync_from_config); g_test_add_func ("/libnm/settings/team/sync_watcher_from_config_all", test_multiple_watchers_sync_from_config); + + g_test_add_func ("/libnm/settings/team-port/sync_from_config_defaults", test_team_port_default); + g_test_add_func ("/libnm/settings/team-port/sync_from_config_queue_id", test_team_port_queue_id); + g_test_add_func ("/libnm/settings/team-port/sync_from_config_prio", test_team_port_prio); + g_test_add_func ("/libnm/settings/team-port/sync_from_config_sticky", test_team_port_sticky); + g_test_add_func ("/libnm/settings/team-port/sync_from_config_lacp_prio", test_team_port_lacp_prio); + g_test_add_func ("/libnm/settings/team-port/sync_from_config_lacp_key", test_team_port_lacp_key); + g_test_add_func ("/libnm/settings/team-port/sycn_from_config_full", test_team_port_full_config); + #endif return g_test_run ();