Commit 3c649e64 authored by Beniamino Galvani's avatar Beniamino Galvani

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
parent 3df3e46d
......@@ -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 */
......
......@@ -25,6 +25,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
......
......@@ -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;
......
......@@ -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));
}
......@@ -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
......
......@@ -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);
......@@ -148,6 +153,27 @@ ensure_teamd_connection (NMDevice *device)
return !!priv->tdc;
}
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)
{
......@@ -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);
}
}
......@@ -695,6 +721,23 @@ nm_device_team_new (const char *iface)
NULL);
}
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);
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment