diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2016-05-16 14:42:41 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2016-05-26 09:16:46 +0200 |
commit | 3c649e6429908e0b83bc176f8349c72ebd61ad60 (patch) | |
tree | 5953cadf8a8262ed54ee62f38fe706570bcf47bb | |
parent | 3df3e46d64f428a44548bb70fff3bb87d4e75ab2 (diff) | |
download | NetworkManager-3c649e6429908e0b83bc176f8349c72ebd61ad60.tar.gz |
team: expose current device configuration through D-Bus and nmcli
Add a new "Config" property to the D-Bus interface for team devices
and show its value through "nmcli device show". The property contains
the full JSON configuration from teamd for the device.
https://bugzilla.redhat.com/show_bug.cgi?id=1310435
-rw-r--r-- | clients/cli/devices.c | 102 | ||||
-rw-r--r-- | introspection/nm-device-team.xml | 7 | ||||
-rw-r--r-- | libnm/libnm.ver | 1 | ||||
-rw-r--r-- | libnm/nm-device-team.c | 40 | ||||
-rw-r--r-- | libnm/nm-device-team.h | 3 | ||||
-rw-r--r-- | src/devices/team/nm-device-team.c | 77 | ||||
-rw-r--r-- | src/devices/team/nm-device-team.h | 3 |
7 files changed, 210 insertions, 23 deletions
diff --git a/clients/cli/devices.c b/clients/cli/devices.c index 65c4be7286..e1688278a4 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -186,7 +186,7 @@ static NmcOutputField nmc_fields_dev_wimax_list[] = { #define NMC_FIELDS_DEV_WIMAX_LIST_COMMON "NSP,SIGNAL,TYPE,DEVICE,ACTIVE" #define NMC_FIELDS_DEV_WIMAX_LIST_FOR_DEV_LIST "NAME,"NMC_FIELDS_DEV_WIMAX_LIST_COMMON -/* Available fields for 'device show' - BOND, TEAM, BRIDGE part */ +/* Available fields for 'device show' - BOND, BRIDGE part */ static NmcOutputField nmc_fields_dev_show_master_prop[] = { {"NAME", N_("NAME")}, /* 0 */ {"SLAVES", N_("SLAVES")}, /* 1 */ @@ -195,6 +195,16 @@ static NmcOutputField nmc_fields_dev_show_master_prop[] = { #define NMC_FIELDS_DEV_SHOW_MASTER_PROP_ALL "NAME,SLAVES" #define NMC_FIELDS_DEV_SHOW_MASTER_PROP_COMMON "NAME,SLAVES" +/* Available fields for 'device show' - TEAM part */ +static NmcOutputField nmc_fields_dev_show_team_prop[] = { + {"NAME", N_("NAME")}, /* 0 */ + {"SLAVES", N_("SLAVES")}, /* 1 */ + {"CONFIG", N_("CONFIG")}, /* 2 */ + {NULL, NULL} +}; +#define NMC_FIELDS_DEV_SHOW_TEAM_PROP_ALL "NAME,SLAVES,CONFIG" +#define NMC_FIELDS_DEV_SHOW_TEAM_PROP_COMMON "NAME,SLAVES,CONFIG" + /* Available fields for 'device show' - VLAN part */ static NmcOutputField nmc_fields_dev_show_vlan_prop[] = { {"NAME", N_("NAME")}, /* 0 */ @@ -234,7 +244,7 @@ static NmcOutputField nmc_fields_dev_show_sections[] = { {"IP6", N_("IP6"), 0, nmc_fields_ip6_config + 1 }, /* 9 */ {"DHCP6", N_("DHCP6"), 0, nmc_fields_dhcp6_config + 1 }, /* 10 */ {"BOND", N_("BOND"), 0, nmc_fields_dev_show_master_prop + 1 }, /* 11 */ - {"TEAM", N_("TEAM"), 0, nmc_fields_dev_show_master_prop + 1 }, /* 12 */ + {"TEAM", N_("TEAM"), 0, nmc_fields_dev_show_team_prop + 1 }, /* 12 */ {"BRIDGE", N_("BRIDGE"), 0, nmc_fields_dev_show_master_prop + 1 }, /* 13 */ {"VLAN", N_("VLAN"), 0, nmc_fields_dev_show_vlan_prop + 1 }, /* 14 */ {"BLUETOOTH", N_("BLUETOOTH"), 0, nmc_fields_dev_show_bluetooth + 1 }, /* 15 */ @@ -840,10 +850,10 @@ get_active_connection_id (NMDevice *device) } static gboolean -print_bond_team_bridge_info (NMDevice *device, - NmCli *nmc, - const char *group_prefix, - const char *one_field) +print_bond_bridge_info (NMDevice *device, + NmCli *nmc, + const char *group_prefix, + const char *one_field) { const GPtrArray *slaves = NULL; GString *slaves_str; @@ -853,10 +863,10 @@ print_bond_team_bridge_info (NMDevice *device, if (NM_IS_DEVICE_BOND (device)) slaves = nm_device_bond_get_slaves (NM_DEVICE_BOND (device)); - else if (NM_IS_DEVICE_TEAM (device)) - slaves = nm_device_team_get_slaves (NM_DEVICE_TEAM (device)); else if (NM_IS_DEVICE_BRIDGE (device)) slaves = nm_device_bridge_get_slaves (NM_DEVICE_BRIDGE (device)); + else + g_return_val_if_reached (FALSE); slaves_str = g_string_new (NULL); for (idx = 0; slaves && idx < slaves->len; idx++) { @@ -891,6 +901,76 @@ print_bond_team_bridge_info (NMDevice *device, return TRUE; } +static char * +sanitize_team_config (const char *config) +{ + char *ret; + int i; + + if (!config) + return NULL; + + ret = g_strdup (config); + + for (i = 0; i < strlen (ret); i++) { + if (ret[i] == '\n') + ret[i] = ' '; + } + + return ret; +} + +static gboolean +print_team_info (NMDevice *device, + NmCli *nmc, + const char *group_prefix, + const char *one_field) +{ + const GPtrArray *slaves = NULL; + GString *slaves_str; + int idx; + NmcOutputField *tmpl, *arr; + size_t tmpl_len; + + if (NM_IS_DEVICE_TEAM (device)) + slaves = nm_device_team_get_slaves (NM_DEVICE_TEAM (device)); + else + g_return_val_if_reached (FALSE); + + slaves_str = g_string_new (NULL); + for (idx = 0; slaves && idx < slaves->len; idx++) { + NMDevice *slave = g_ptr_array_index (slaves, idx); + const char *iface = nm_device_get_iface (slave); + + if (iface) { + g_string_append (slaves_str, iface); + g_string_append_c (slaves_str, ' '); + } + } + if (slaves_str->len > 0) + g_string_truncate (slaves_str, slaves_str->len-1); /* Chop off last space */ + + tmpl = nmc_fields_dev_show_team_prop; + tmpl_len = sizeof (nmc_fields_dev_show_team_prop); + nmc->print_fields.indices = parse_output_fields (one_field ? one_field : NMC_FIELDS_DEV_SHOW_TEAM_PROP_ALL, + tmpl, FALSE, NULL, NULL); + arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES); + g_ptr_array_add (nmc->output_data, arr); + + arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX); + set_val_strc (arr, 0, group_prefix); /* TEAM */ + set_val_str (arr, 1, slaves_str->str); + set_val_str (arr, 2, sanitize_team_config (nm_device_team_get_config (NM_DEVICE_TEAM (device)))); + g_ptr_array_add (nmc->output_data, arr); + + print_data (nmc); /* Print all data */ + + g_string_free (slaves_str, FALSE); + nmc_empty_output_fields (nmc); + + return TRUE; +} + static gboolean show_device_info (NMDevice *device, NmCli *nmc) { @@ -1146,19 +1226,19 @@ show_device_info (NMDevice *device, NmCli *nmc) /* Bond specific information */ if (NM_IS_DEVICE_BOND (device)) { if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[11].name)) - was_output = print_bond_team_bridge_info (device, nmc, nmc_fields_dev_show_sections[11].name, section_fld); + was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[11].name, section_fld); } /* Team specific information */ if (NM_IS_DEVICE_TEAM (device)) { if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[12].name)) - was_output = print_bond_team_bridge_info (device, nmc, nmc_fields_dev_show_sections[12].name, section_fld); + was_output = print_team_info (device, nmc, nmc_fields_dev_show_sections[12].name, section_fld); } /* Bridge specific information */ if (NM_IS_DEVICE_BRIDGE (device)) { if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[13].name)) - was_output = print_bond_team_bridge_info (device, nmc, nmc_fields_dev_show_sections[13].name, section_fld); + was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[13].name, section_fld); } /* VLAN-specific information */ diff --git a/introspection/nm-device-team.xml b/introspection/nm-device-team.xml index 05bbbafe46..64faaec4b0 100644 --- a/introspection/nm-device-team.xml +++ b/introspection/nm-device-team.xml @@ -26,6 +26,13 @@ <property name="Slaves" type="ao" access="read"/> <!-- + Config: + + The JSON configuration currently applied on the device. + --> + <property name="Config" type="s" access="read" /> + + <!-- PropertiesChanged: @properties: A dictionary mapping property names to variant boxed values --> diff --git a/libnm/libnm.ver b/libnm/libnm.ver index f8e2c4eb2d..abd4c57e44 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1061,6 +1061,7 @@ global: libnm_1_4_0 { global: + nm_device_team_get_config; nm_setting_ip_config_get_dns_priority; nm_vpn_editor_plugin_load; nm_vpn_plugin_info_get_auth_dialog; diff --git a/libnm/nm-device-team.c b/libnm/nm-device-team.c index b855d5ec38..3955e10561 100644 --- a/libnm/nm-device-team.c +++ b/libnm/nm-device-team.c @@ -39,6 +39,7 @@ typedef struct { char *hw_address; gboolean carrier; GPtrArray *slaves; + char *config; } NMDeviceTeamPrivate; enum { @@ -46,6 +47,7 @@ enum { PROP_HW_ADDRESS, PROP_CARRIER, PROP_SLAVES, + PROP_CONFIG, LAST_PROP }; @@ -101,6 +103,25 @@ nm_device_team_get_slaves (NMDeviceTeam *device) return NM_DEVICE_TEAM_GET_PRIVATE (device)->slaves; } +/** + * nm_device_team_get_config: + * @device: a #NMDeviceTeam + * + * Gets the current JSON configuration of the #NMDeviceTeam + * + * Returns: the current configuration. This is the internal string used by the + * device, and must not be modified. + * + * Since: 1.4 + **/ +const char * +nm_device_team_get_config (NMDeviceTeam *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_TEAM (device), NULL); + + return NM_DEVICE_TEAM_GET_PRIVATE (device)->config; +} + static const char * get_hw_address (NMDevice *device) { @@ -150,6 +171,7 @@ init_dbus (NMObject *object) { NM_DEVICE_TEAM_HW_ADDRESS, &priv->hw_address }, { NM_DEVICE_TEAM_CARRIER, &priv->carrier }, { NM_DEVICE_TEAM_SLAVES, &priv->slaves, NULL, NM_TYPE_DEVICE }, + { NM_DEVICE_TEAM_CONFIG, &priv->config }, { NULL }, }; @@ -176,6 +198,7 @@ finalize (GObject *object) NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (object); g_free (priv->hw_address); + g_free (priv->config); G_OBJECT_CLASS (nm_device_team_parent_class)->finalize (object); } @@ -198,6 +221,9 @@ get_property (GObject *object, case PROP_SLAVES: g_value_take_boxed (value, _nm_utils_copy_object_array (nm_device_team_get_slaves (device))); break; + case PROP_CONFIG: + g_value_set_string (value, nm_device_team_get_config (device)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -265,4 +291,18 @@ nm_device_team_class_init (NMDeviceTeamClass *team_class) G_TYPE_PTR_ARRAY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + /** + * NMDeviceTeam:config: + * + * The current JSON configuration of the device. + * + * Since: 1.4 + **/ + g_object_class_install_property + (object_class, PROP_CONFIG, + g_param_spec_string (NM_DEVICE_TEAM_CONFIG, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); } diff --git a/libnm/nm-device-team.h b/libnm/nm-device-team.h index a9b71c6ab0..522e3d29c0 100644 --- a/libnm/nm-device-team.h +++ b/libnm/nm-device-team.h @@ -39,6 +39,7 @@ G_BEGIN_DECLS #define NM_DEVICE_TEAM_HW_ADDRESS "hw-address" #define NM_DEVICE_TEAM_CARRIER "carrier" #define NM_DEVICE_TEAM_SLAVES "slaves" +#define NM_DEVICE_TEAM_CONFIG "config" /** * NMDeviceTeam: @@ -59,6 +60,8 @@ GType nm_device_team_get_type (void); const char *nm_device_team_get_hw_address (NMDeviceTeam *device); gboolean nm_device_team_get_carrier (NMDeviceTeam *device); const GPtrArray *nm_device_team_get_slaves (NMDeviceTeam *device); +NM_AVAILABLE_IN_1_4 +const char *nm_device_team_get_config (NMDeviceTeam *device); G_END_DECLS diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 47930f437c..fd71899622 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -45,6 +45,10 @@ G_DEFINE_TYPE (NMDeviceTeam, nm_device_team, NM_TYPE_DEVICE) #define NM_DEVICE_TEAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_TEAM, NMDeviceTeamPrivate)) +NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceTeam, + PROP_CONFIG, +); + typedef struct { struct teamdctl *tdc; GPid teamd_pid; @@ -52,6 +56,7 @@ typedef struct { guint teamd_timeout; guint teamd_dbus_watch; gboolean teamd_dbus_name_owned; + char *config; } NMDeviceTeamPrivate; static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team); @@ -149,6 +154,27 @@ ensure_teamd_connection (NMDevice *device) } static void +teamd_read_config (NMDevice *device) +{ + NMDeviceTeam *self = NM_DEVICE_TEAM (device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); + char *config = NULL; + int err; + + if (priv->tdc) { + err = teamdctl_config_get_raw_direct (priv->tdc, &config); + if (err) + _LOGI (LOGD_TEAM, "failed to read teamd config (err=%d)", err); + } + + if (!nm_streq0 (config, priv->config)) { + g_free (priv->config); + priv->config = g_strdup (config); + _notify (self, PROP_CONFIG); + } +} + +static void update_connection (NMDevice *device, NMConnection *connection) { NMDeviceTeam *self = NM_DEVICE_TEAM (device); @@ -159,18 +185,12 @@ update_connection (NMDevice *device, NMConnection *connection) s_team = (NMSettingTeam *) nm_setting_team_new (); nm_connection_add_setting (connection, (NMSetting *) s_team); } - g_object_set (G_OBJECT (s_team), NM_SETTING_TEAM_CONFIG, NULL, NULL); - if (ensure_teamd_connection (device)) { - const char *config = NULL; - int err; + /* Read the configuration only if not already set */ + if (!priv->config && ensure_teamd_connection (device)) + teamd_read_config (device); - err = teamdctl_config_get_raw_direct (priv->tdc, (char **)&config); - if (err == 0) - g_object_set (G_OBJECT (s_team), NM_SETTING_TEAM_CONFIG, config, NULL); - else - _LOGE (LOGD_TEAM, "failed to read teamd config (err=%d)", err); - } + g_object_set (G_OBJECT (s_team), NM_SETTING_TEAM_CONFIG, priv->config, NULL); } /******************************************************************/ @@ -279,6 +299,11 @@ teamd_timeout_cb (gpointer user_data) g_warn_if_fail (nm_device_is_activating (device)); nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); + } else { + /* Read again the configuration after the timeout since it might + * have changed. + */ + teamd_read_config (device); } return G_SOURCE_REMOVE; @@ -331,9 +356,10 @@ teamd_dbus_appeared (GDBusConnection *connection, */ success = ensure_teamd_connection (device); if (nm_device_get_state (device) == NM_DEVICE_STATE_PREPARE) { - if (success) + if (success) { + teamd_read_config (device); nm_device_activate_schedule_stage2_device_config (device); - else if (!nm_device_uses_assumed_connection (device)) + } else if (!nm_device_uses_assumed_connection (device)) nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); } } @@ -696,6 +722,23 @@ nm_device_team_new (const char *iface) } static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMDeviceTeam *self = NM_DEVICE_TEAM (object); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); + + switch (prop_id) { + case PROP_CONFIG: + g_value_set_string (value, priv->config); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void nm_device_team_init (NMDeviceTeam * self) { } @@ -733,6 +776,7 @@ dispose (GObject *object) } teamd_cleanup (device, TRUE); + g_clear_pointer (&priv->config, g_free); G_OBJECT_CLASS (nm_device_team_parent_class)->dispose (object); } @@ -749,6 +793,7 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) object_class->constructed = constructed; object_class->dispose = dispose; + object_class->get_property = get_property; parent_class->create_and_realize = create_and_realize; parent_class->get_generic_capabilities = get_generic_capabilities; @@ -765,6 +810,14 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; + obj_properties[PROP_CONFIG] = + g_param_spec_string (NM_DEVICE_TEAM_CONFIG, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), NMDBUS_TYPE_DEVICE_TEAM_SKELETON, NULL); diff --git a/src/devices/team/nm-device-team.h b/src/devices/team/nm-device-team.h index 0e81afa744..27bd8227db 100644 --- a/src/devices/team/nm-device-team.h +++ b/src/devices/team/nm-device-team.h @@ -32,6 +32,9 @@ G_BEGIN_DECLS #define NM_IS_DEVICE_TEAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_TEAM)) #define NM_DEVICE_TEAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeamClass)) +/* Properties */ +#define NM_DEVICE_TEAM_CONFIG "config" + typedef NMDevice NMDeviceTeam; typedef NMDeviceClass NMDeviceTeamClass; |