all: merge branch 'th/device-statistics'

Add support to expose tx/rx statistics per device

https://mail.gnome.org/archives/networkmanager-list/2016-August/msg00045.html
This commit is contained in:
Thomas Haller
2016-08-17 16:13:16 +02:00
21 changed files with 304 additions and 14 deletions

View File

@@ -439,6 +439,8 @@ permission_to_string (NMClientPermission perm)
return NM_AUTH_PERMISSION_RELOAD; return NM_AUTH_PERMISSION_RELOAD;
case NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK: case NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK:
return NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK; return NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK;
case NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS:
return NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS;
default: default:
return _("unknown"); return _("unknown");
} }

View File

@@ -73,6 +73,7 @@ content_files = \
$(top_builddir)/introspection/nmdbus-settings-org.freedesktop.NetworkManager.Settings.xml \ $(top_builddir)/introspection/nmdbus-settings-org.freedesktop.NetworkManager.Settings.xml \
$(top_builddir)/introspection/nmdbus-device-ethernet-org.freedesktop.NetworkManager.Device.Wired.xml \ $(top_builddir)/introspection/nmdbus-device-ethernet-org.freedesktop.NetworkManager.Device.Wired.xml \
$(top_builddir)/introspection/nmdbus-ip4-config-org.freedesktop.NetworkManager.IP4Config.xml \ $(top_builddir)/introspection/nmdbus-ip4-config-org.freedesktop.NetworkManager.IP4Config.xml \
$(top_builddir)/introspection/nmdbus-device-statistics-org.freedesktop.NetworkManager.Device.Statistics.xml \
$(top_builddir)/libnm-core/nm-dbus-types.xml \ $(top_builddir)/libnm-core/nm-dbus-types.xml \
$(top_builddir)/libnm-core/nm-vpn-dbus-types.xml \ $(top_builddir)/libnm-core/nm-vpn-dbus-types.xml \
$(top_builddir)/man/nmcli.xml \ $(top_builddir)/man/nmcli.xml \

View File

@@ -98,6 +98,7 @@
<xi:include href="../../introspection/nmdbus-ip6-config-org.freedesktop.NetworkManager.IP6Config.xml"/> <xi:include href="../../introspection/nmdbus-ip6-config-org.freedesktop.NetworkManager.IP6Config.xml"/>
<xi:include href="../../introspection/nmdbus-vpn-plugin-org.freedesktop.NetworkManager.VPN.Plugin.xml"/> <xi:include href="../../introspection/nmdbus-vpn-plugin-org.freedesktop.NetworkManager.VPN.Plugin.xml"/>
<xi:include href="../../introspection/nmdbus-secret-agent-org.freedesktop.NetworkManager.SecretAgent.xml"/> <xi:include href="../../introspection/nmdbus-secret-agent-org.freedesktop.NetworkManager.SecretAgent.xml"/>
<xi:include href="../../introspection/nmdbus-device-statistics-org.freedesktop.NetworkManager.Device.Statistics.xml"/>
</section> </section>
<section id="dbus-types"> <section id="dbus-types">
<title>Types</title> <title>Types</title>

View File

@@ -43,6 +43,8 @@ nodist_libnmdbus_la_SOURCES = \
nmdbus-device-modem.h \ nmdbus-device-modem.h \
nmdbus-device-olpc-mesh.c \ nmdbus-device-olpc-mesh.c \
nmdbus-device-olpc-mesh.h \ nmdbus-device-olpc-mesh.h \
nmdbus-device-statistics.c \
nmdbus-device-statistics.h \
nmdbus-device-team.c \ nmdbus-device-team.c \
nmdbus-device-team.h \ nmdbus-device-team.h \
nmdbus-device-tun.c \ nmdbus-device-tun.c \
@@ -114,7 +116,8 @@ DBUS_INTERFACE_DOCS = \
nmdbus-device-veth-org.freedesktop.NetworkManager.Device.Veth.xml \ nmdbus-device-veth-org.freedesktop.NetworkManager.Device.Veth.xml \
nmdbus-settings-org.freedesktop.NetworkManager.Settings.xml \ nmdbus-settings-org.freedesktop.NetworkManager.Settings.xml \
nmdbus-device-ethernet-org.freedesktop.NetworkManager.Device.Wired.xml \ nmdbus-device-ethernet-org.freedesktop.NetworkManager.Device.Wired.xml \
nmdbus-ip4-config-org.freedesktop.NetworkManager.IP4Config.xml nmdbus-ip4-config-org.freedesktop.NetworkManager.IP4Config.xml \
nmdbus-device-statistics-org.freedesktop.NetworkManager.Device.Statistics.xml
define _make_nmdbus_rule define _make_nmdbus_rule
$(1): $(patsubst nmdbus-%.c,nm-%.xml,$(1)) $(1): $(patsubst nmdbus-%.c,nm-%.xml,$(1))
@@ -154,6 +157,7 @@ EXTRA_DIST = \
nm-device-macvlan.xml \ nm-device-macvlan.xml \
nm-device-modem.xml \ nm-device-modem.xml \
nm-device-olpc-mesh.xml \ nm-device-olpc-mesh.xml \
nm-device-statistics.xml \
nm-device-team.xml \ nm-device-team.xml \
nm-device-tun.xml \ nm-device-tun.xml \
nm-device-veth.xml \ nm-device-veth.xml \

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<node name="/">
<interface name="org.freedesktop.NetworkManager.Device.Statistics">
<!--
RefreshRateMs:
Refresh rate of the rest of properties of this interface. The properties
are guaranteed to be refreshed each RefreshRateMs milliseconds in case
the underlying counter has changed too.
If zero, there is no guaranteed refresh rate of the properties.
-->
<property name="RefreshRateMs" type="u" access="readwrite"/>
<!--
TxBytes:
Number of transmitted bytes
-->
<property name="TxBytes" type="t" access="read"/>
<!--
RxBytes:
Number of received bytes
-->
<property name="RxBytes" type="t" access="read"/>
<!--
PropertiesChanged:
@properties: A dictionary mapping property names to variant boxed values
-->
<signal name="PropertiesChanged">
<arg name="properties" type="a{sv}"/>
</signal>
</interface>
</node>

View File

@@ -68,6 +68,7 @@
#define NM_DBUS_INTERFACE_DEVICE_VXLAN NM_DBUS_INTERFACE_DEVICE ".Vxlan" #define NM_DBUS_INTERFACE_DEVICE_VXLAN NM_DBUS_INTERFACE_DEVICE ".Vxlan"
#define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre" #define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre"
#define NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL NM_DBUS_INTERFACE_DEVICE ".IPTunnel" #define NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL NM_DBUS_INTERFACE_DEVICE ".IPTunnel"
#define NM_DBUS_INTERFACE_DEVICE_STATISTICS NM_DBUS_INTERFACE_DEVICE ".Statistics"
#define NM_DBUS_INTERFACE_SETTINGS "org.freedesktop.NetworkManager.Settings" #define NM_DBUS_INTERFACE_SETTINGS "org.freedesktop.NetworkManager.Settings"
#define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManager/Settings" #define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManager/Settings"

View File

@@ -240,6 +240,8 @@ nm_permission_to_client (const char *nm)
return NM_CLIENT_PERMISSION_RELOAD; return NM_CLIENT_PERMISSION_RELOAD;
else if (!strcmp (nm, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK)) else if (!strcmp (nm, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK))
return NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK; return NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK;
else if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS))
return NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS;
return NM_CLIENT_PERMISSION_NONE; return NM_CLIENT_PERMISSION_NONE;
} }

View File

@@ -89,6 +89,8 @@ G_BEGIN_DECLS
* @NM_CLIENT_PERMISSION_RELOAD: controls access to Reload. * @NM_CLIENT_PERMISSION_RELOAD: controls access to Reload.
* persistent hostname can be changed * persistent hostname can be changed
* @NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK: permission to create checkpoints. * @NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK: permission to create checkpoints.
* @NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS: controls whether device
* statistics can be globally enabled or disabled
* @NM_CLIENT_PERMISSION_LAST: a reserved boundary value * @NM_CLIENT_PERMISSION_LAST: a reserved boundary value
* *
* #NMClientPermission values indicate various permissions that NetworkManager * #NMClientPermission values indicate various permissions that NetworkManager
@@ -110,8 +112,9 @@ typedef enum {
NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS = 12, NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS = 12,
NM_CLIENT_PERMISSION_RELOAD = 13, NM_CLIENT_PERMISSION_RELOAD = 13,
NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK = 14, NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK = 14,
NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS = 15,
NM_CLIENT_PERMISSION_LAST = 14, NM_CLIENT_PERMISSION_LAST = 15,
} NMClientPermission; } NMClientPermission;
/** /**

View File

@@ -98,6 +98,8 @@ G_BEGIN_DECLS
* DNS configuration * DNS configuration
* @NM_CLIENT_PERMISSION_RELOAD: controls access to Reload. * @NM_CLIENT_PERMISSION_RELOAD: controls access to Reload.
* @NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK: permission to create checkpoints. * @NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK: permission to create checkpoints.
* @NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS: controls whether device
* statistics can be globally enabled or disabled
* @NM_CLIENT_PERMISSION_LAST: a reserved boundary value * @NM_CLIENT_PERMISSION_LAST: a reserved boundary value
* *
* #NMClientPermission values indicate various permissions that NetworkManager * #NMClientPermission values indicate various permissions that NetworkManager
@@ -119,8 +121,9 @@ typedef enum {
NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS = 12, NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS = 12,
NM_CLIENT_PERMISSION_RELOAD = 13, NM_CLIENT_PERMISSION_RELOAD = 13,
NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK = 14, NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK = 14,
NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS = 15,
NM_CLIENT_PERMISSION_LAST = 14, NM_CLIENT_PERMISSION_LAST = 15,
} NMClientPermission; } NMClientPermission;
/** /**

View File

@@ -234,6 +234,8 @@ nm_permission_to_client (const char *nm)
return NM_CLIENT_PERMISSION_RELOAD; return NM_CLIENT_PERMISSION_RELOAD;
else if (!strcmp (nm, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK)) else if (!strcmp (nm, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK))
return NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK; return NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK;
else if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS))
return NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS;
return NM_CLIENT_PERMISSION_NONE; return NM_CLIENT_PERMISSION_NONE;
} }

View File

@@ -142,5 +142,14 @@
</defaults> </defaults>
</action> </action>
<action id="org.freedesktop.NetworkManager.enable-disable-statistics">
<_description>Enable or disable device statistics</_description>
<_message>System policy prevents enabling or disabling device statistics</_message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
</policyconfig> </policyconfig>

View File

@@ -38,6 +38,7 @@
#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS "org.freedesktop.NetworkManager.settings.modify.global-dns" #define NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS "org.freedesktop.NetworkManager.settings.modify.global-dns"
#define NM_AUTH_PERMISSION_RELOAD "org.freedesktop.NetworkManager.reload" #define NM_AUTH_PERMISSION_RELOAD "org.freedesktop.NetworkManager.reload"
#define NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK "org.freedesktop.NetworkManager.checkpoint-rollback" #define NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK "org.freedesktop.NetworkManager.checkpoint-rollback"
#define NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS "org.freedesktop.NetworkManager.enable-disable-statistics"
#define NM_CLONED_MAC_PRESERVE "preserve" #define NM_CLONED_MAC_PRESERVE "preserve"
#define NM_CLONED_MAC_PERMANENT "permanent" #define NM_CLONED_MAC_PERMANENT "permanent"

View File

@@ -71,6 +71,7 @@
_LOG_DECLARE_SELF (NMDevice); _LOG_DECLARE_SELF (NMDevice);
#include "nmdbus-device.h" #include "nmdbus-device.h"
#include "nmdbus-device-statistics.h"
G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_EXPORTED_OBJECT) G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_EXPORTED_OBJECT)
@@ -138,6 +139,9 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDevice,
PROP_LLDP_NEIGHBORS, PROP_LLDP_NEIGHBORS,
PROP_REAL, PROP_REAL,
PROP_SLAVES, PROP_SLAVES,
PROP_REFRESH_RATE_MS,
PROP_TX_BYTES,
PROP_RX_BYTES,
); );
#define DEFAULT_AUTOCONNECT TRUE #define DEFAULT_AUTOCONNECT TRUE
@@ -407,6 +411,14 @@ typedef struct _NMDevicePrivate {
NMLldpListener *lldp_listener; NMLldpListener *lldp_listener;
guint check_delete_unrealized_id; guint check_delete_unrealized_id;
struct {
guint timeout_id;
guint refresh_rate_ms;
guint64 tx_bytes;
guint64 rx_bytes;
} stats;
} NMDevicePrivate; } NMDevicePrivate;
static gboolean nm_device_set_ip4_config (NMDevice *self, static gboolean nm_device_set_ip4_config (NMDevice *self,
@@ -769,6 +781,108 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
g_free (old_ip_iface); g_free (old_ip_iface);
} }
/*****************************************************************************/
static void
_stats_update_counters (NMDevice *self,
guint64 tx_bytes,
guint64 rx_bytes)
{
NMDevicePrivate *priv;
priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->stats.tx_bytes != tx_bytes) {
priv->stats.tx_bytes = tx_bytes;
_notify (self, PROP_TX_BYTES);
}
if (priv->stats.rx_bytes != rx_bytes) {
priv->stats.rx_bytes = rx_bytes;
_notify (self, PROP_RX_BYTES);
}
}
static void
_stats_update_counters_from_pllink (NMDevice *self, const NMPlatformLink *pllink)
{
_stats_update_counters (self, pllink->tx_bytes, pllink->rx_bytes);
}
static gboolean
_stats_timeout_cb (gpointer user_data)
{
NMDevice *self = user_data;
int ifindex;
ifindex = nm_device_get_ip_ifindex (self);
_LOGT (LOGD_DEVICE, "stats: refresh %d", ifindex);
if (ifindex > 0)
nm_platform_link_refresh (NM_PLATFORM_GET, ifindex);
return G_SOURCE_CONTINUE;
}
static guint
_stats_refresh_rate_real (guint refresh_rate_ms)
{
const guint STATS_REFRESH_RATE_MS_MIN = 200;
if (refresh_rate_ms == 0)
return 0;
if (refresh_rate_ms < STATS_REFRESH_RATE_MS_MIN) {
/* you cannot set the refresh-rate arbitrarly small. E.g.
* setting to 1ms is just killing. Have a lowest number. */
return STATS_REFRESH_RATE_MS_MIN;
}
return refresh_rate_ms;
}
static void
_stats_set_refresh_rate (NMDevice *self, guint refresh_rate_ms)
{
NMDevicePrivate *priv;
int ifindex;
guint old_rate;
priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->stats.refresh_rate_ms == refresh_rate_ms)
return;
old_rate = priv->stats.refresh_rate_ms;
priv->stats.refresh_rate_ms = refresh_rate_ms;
_notify (self, PROP_REFRESH_RATE_MS);
_LOGD (LOGD_DEVICE, "stats: set refresh to %u ms", priv->stats.refresh_rate_ms);
if (!nm_device_is_real (self))
return;
refresh_rate_ms = _stats_refresh_rate_real (refresh_rate_ms);
if (_stats_refresh_rate_real (old_rate) == refresh_rate_ms)
return;
nm_clear_g_source (&priv->stats.timeout_id);
if (!refresh_rate_ms)
return;
/* trigger an inital refresh of the data whenever the refresh-rate changes.
* As we process the result in an idle handler with device_link_changed(),
* we don't get the result right away. */
ifindex = nm_device_get_ip_ifindex (self);
if (ifindex > 0)
nm_platform_link_refresh (NM_PLATFORM_GET, ifindex);
priv->stats.timeout_id = g_timeout_add (refresh_rate_ms, _stats_timeout_cb, self);
}
/*****************************************************************************/
static gboolean static gboolean
get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid)
{ {
@@ -1712,6 +1826,9 @@ device_link_changed (NMDevice *self)
_notify (self, PROP_DRIVER); _notify (self, PROP_DRIVER);
} }
if (ifindex == nm_device_get_ip_ifindex (self))
_stats_update_counters_from_pllink (self, &info);
had_hw_addr = (priv->hw_addr != NULL); had_hw_addr = (priv->hw_addr != NULL);
nm_device_update_hw_address (self); nm_device_update_hw_address (self);
got_hw_addr = (!had_hw_addr && priv->hw_addr); got_hw_addr = (!had_hw_addr && priv->hw_addr);
@@ -1840,6 +1957,8 @@ device_ip_link_changed (NMDevice *self)
if (!pllink) if (!pllink)
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
_stats_update_counters_from_pllink (self, pllink);
if (pllink->name[0] && g_strcmp0 (priv->ip_iface, pllink->name)) { if (pllink->name[0] && g_strcmp0 (priv->ip_iface, pllink->name)) {
_LOGI (LOGD_DEVICE, "interface index %d renamed ip_iface (%d) from '%s' to '%s'", _LOGI (LOGD_DEVICE, "interface index %d renamed ip_iface (%d) from '%s' to '%s'",
priv->ifindex, nm_device_get_ip_ifindex (self), priv->ifindex, nm_device_get_ip_ifindex (self),
@@ -1850,6 +1969,7 @@ device_ip_link_changed (NMDevice *self)
_notify (self, PROP_IP_IFACE); _notify (self, PROP_IP_IFACE);
nm_device_update_dynamic_ip_setup (self); nm_device_update_dynamic_ip_setup (self);
} }
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
@@ -1955,6 +2075,8 @@ nm_device_realize_start (NMDevice *self,
gboolean *out_compatible, gboolean *out_compatible,
GError **error) GError **error)
{ {
NMPlatformLink plink_copy;
NM_SET_OUT (out_compatible, TRUE); NM_SET_OUT (out_compatible, TRUE);
if (plink) { if (plink) {
@@ -1969,6 +2091,10 @@ nm_device_realize_start (NMDevice *self,
return FALSE; return FALSE;
} }
if (plink) {
plink_copy = *plink;
plink = &plink_copy;
}
realize_start_setup (self, plink); realize_start_setup (self, plink);
return TRUE; return TRUE;
@@ -2102,6 +2228,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
static guint32 id = 0; static guint32 id = 0;
NMDeviceCapabilities capabilities = 0; NMDeviceCapabilities capabilities = 0;
NMConfig *config; NMConfig *config;
guint real_rate;
g_return_if_fail (NM_IS_DEVICE (self)); g_return_if_fail (NM_IS_DEVICE (self));
@@ -2125,6 +2252,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
if (plink) { if (plink) {
g_return_if_fail (link_type_compatible (self, plink->type, NULL, NULL)); g_return_if_fail (link_type_compatible (self, plink->type, NULL, NULL));
update_device_from_platform_link (self, plink); update_device_from_platform_link (self, plink);
_stats_update_counters_from_pllink (self, plink);
} }
if (priv->ifindex > 0) { if (priv->ifindex > 0) {
@@ -2193,6 +2321,11 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
priv->carrier = TRUE; priv->carrier = TRUE;
} }
nm_assert (!priv->stats.timeout_id);
real_rate = _stats_refresh_rate_real (priv->stats.refresh_rate_ms);
if (real_rate)
priv->stats.timeout_id = g_timeout_add (real_rate, _stats_timeout_cb, self);
klass->realize_start_notify (self, plink); klass->realize_start_notify (self, plink);
/* Do not manage externally created software devices until they are IFF_UP /* Do not manage externally created software devices until they are IFF_UP
@@ -2365,6 +2498,9 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
_notify (self, PROP_PHYSICAL_PORT_ID); _notify (self, PROP_PHYSICAL_PORT_ID);
} }
nm_clear_g_source (&priv->stats.timeout_id);
_stats_update_counters (self, 0, 0);
priv->hw_addr_type = HW_ADDR_TYPE_UNSET; priv->hw_addr_type = HW_ADDR_TYPE_UNSET;
g_clear_pointer (&priv->hw_addr_perm, g_free); g_clear_pointer (&priv->hw_addr_perm, g_free);
_notify (self, PROP_PERM_HW_ADDRESS); _notify (self, PROP_PERM_HW_ADDRESS);
@@ -12080,6 +12216,8 @@ dispose (GObject *object)
nm_clear_g_source (&priv->check_delete_unrealized_id); nm_clear_g_source (&priv->check_delete_unrealized_id);
nm_clear_g_source (&priv->stats.timeout_id);
link_disconnect_action_cancel (self); link_disconnect_action_cancel (self);
if (priv->settings) { if (priv->settings) {
@@ -12237,6 +12375,9 @@ set_property (GObject *object, guint prop_id,
/* construct only */ /* construct only */
priv->hw_addr_perm = g_value_dup_string (value); priv->hw_addr_perm = g_value_dup_string (value);
break; break;
case PROP_REFRESH_RATE_MS:
_stats_set_refresh_rate (self, g_value_get_uint (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@@ -12399,6 +12540,15 @@ get_property (GObject *object, guint prop_id,
g_value_take_boxed (value, slave_list); g_value_take_boxed (value, slave_list);
break; break;
} }
case PROP_REFRESH_RATE_MS:
g_value_set_uint (value, priv->stats.refresh_rate_ms);
break;
case PROP_TX_BYTES:
g_value_set_uint64 (value, priv->stats.tx_bytes);
break;
case PROP_RX_BYTES:
g_value_set_uint64 (value, priv->stats.rx_bytes);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@@ -12649,6 +12799,23 @@ nm_device_class_init (NMDeviceClass *klass)
G_PARAM_READABLE | G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS); G_PARAM_STATIC_STRINGS);
/* Statistics */
obj_properties[PROP_REFRESH_RATE_MS] =
g_param_spec_uint (NM_DEVICE_STATISTICS_REFRESH_RATE_MS, "", "",
0, UINT32_MAX, 0,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_TX_BYTES] =
g_param_spec_uint64 (NM_DEVICE_STATISTICS_TX_BYTES, "", "",
0, UINT64_MAX, 0,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_RX_BYTES] =
g_param_spec_uint64 (NM_DEVICE_STATISTICS_RX_BYTES, "", "",
0, UINT64_MAX, 0,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
/* Signals */ /* Signals */
@@ -12719,4 +12886,8 @@ nm_device_class_init (NMDeviceClass *klass)
"Disconnect", impl_device_disconnect, "Disconnect", impl_device_disconnect,
"Delete", impl_device_delete, "Delete", impl_device_delete,
NULL); NULL);
nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
NMDBUS_TYPE_DEVICE_STATISTICS_SKELETON,
NULL);
} }

View File

@@ -88,6 +88,10 @@
#define NM_DEVICE_STATE_CHANGED "state-changed" #define NM_DEVICE_STATE_CHANGED "state-changed"
#define NM_DEVICE_LINK_INITIALIZED "link-initialized" #define NM_DEVICE_LINK_INITIALIZED "link-initialized"
#define NM_DEVICE_STATISTICS_REFRESH_RATE_MS "refresh-rate-ms"
#define NM_DEVICE_STATISTICS_TX_BYTES "tx-bytes"
#define NM_DEVICE_STATISTICS_RX_BYTES "rx-bytes"
G_BEGIN_DECLS G_BEGIN_DECLS
#define NM_TYPE_DEVICE (nm_device_get_type ()) #define NM_TYPE_DEVICE (nm_device_get_type ())

View File

@@ -57,6 +57,7 @@ typedef struct {
#define NM_AUDIT_OP_SLEEP_CONTROL "sleep-control" #define NM_AUDIT_OP_SLEEP_CONTROL "sleep-control"
#define NM_AUDIT_OP_NET_CONTROL "networking-control" #define NM_AUDIT_OP_NET_CONTROL "networking-control"
#define NM_AUDIT_OP_RADIO_CONTROL "radio-control" #define NM_AUDIT_OP_RADIO_CONTROL "radio-control"
#define NM_AUDIT_OP_STATISTICS "statistics"
#define NM_AUDIT_OP_DEVICE_AUTOCONNECT "device-autoconnect" #define NM_AUDIT_OP_DEVICE_AUTOCONNECT "device-autoconnect"
#define NM_AUDIT_OP_DEVICE_DISCONNECT "device-disconnect" #define NM_AUDIT_OP_DEVICE_DISCONNECT "device-disconnect"

View File

@@ -257,12 +257,16 @@ nm_exported_object_class_add_interface (NMExportedObjectClass *object_class,
g_return_if_fail (NM_IS_EXPORTED_OBJECT_CLASS (object_class)); g_return_if_fail (NM_IS_EXPORTED_OBJECT_CLASS (object_class));
g_return_if_fail (g_type_is_a (dbus_skeleton_type, G_TYPE_DBUS_INTERFACE_SKELETON)); g_return_if_fail (g_type_is_a (dbus_skeleton_type, G_TYPE_DBUS_INTERFACE_SKELETON));
classinfo = g_slice_new (NMExportedObjectClassInfo); classinfo = g_type_get_qdata (G_TYPE_FROM_CLASS (object_class),
classinfo->skeleton_types = NULL; nm_exported_object_class_info_quark ());
classinfo->methods = g_array_new (FALSE, FALSE, sizeof (NMExportedObjectDBusMethodImpl)); if (!classinfo) {
classinfo->properties = g_hash_table_new (g_str_hash, g_str_equal); classinfo = g_slice_new (NMExportedObjectClassInfo);
g_type_set_qdata (G_TYPE_FROM_CLASS (object_class), classinfo->skeleton_types = NULL;
nm_exported_object_class_info_quark (), classinfo); classinfo->methods = g_array_new (FALSE, FALSE, sizeof (NMExportedObjectDBusMethodImpl));
classinfo->properties = g_hash_table_new (g_str_hash, g_str_equal);
g_type_set_qdata (G_TYPE_FROM_CLASS (object_class),
nm_exported_object_class_info_quark (), classinfo);
}
classinfo->skeleton_types = g_slist_prepend (classinfo->skeleton_types, classinfo->skeleton_types = g_slist_prepend (classinfo->skeleton_types,
GSIZE_TO_POINTER (dbus_skeleton_type)); GSIZE_TO_POINTER (dbus_skeleton_type));
@@ -342,8 +346,6 @@ nm_exported_object_class_add_interface (NMExportedObjectClass *object_class,
} }
} }
g_assert_cmpint (n_method_signals, ==, classinfo->methods->len);
g_type_class_unref (dbus_object_class); g_type_class_unref (dbus_object_class);
} }

View File

@@ -4415,6 +4415,7 @@ get_permissions_done_cb (NMAuthChain *chain,
get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS); get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS);
get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_RELOAD); get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_RELOAD);
get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK); get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK);
get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS);
g_dbus_method_invocation_return_value (context, g_dbus_method_invocation_return_value (context,
g_variant_new ("(a{ss})", &results)); g_variant_new ("(a{ss})", &results));
@@ -4455,6 +4456,7 @@ impl_manager_get_permissions (NMManager *self,
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS, FALSE); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS, FALSE);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_RELOAD, FALSE); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_RELOAD, FALSE);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, FALSE); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, FALSE);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS, FALSE);
} }
static void static void
@@ -4915,6 +4917,10 @@ prop_set_auth_done_cb (NMAuthChain *chain,
/* ... but set the property on the @object itself. It would be correct to set the property /* ... but set the property on the @object itself. It would be correct to set the property
* on the skeleton interface, but as it is now, the result is the same. */ * on the skeleton interface, but as it is now, the result is the same. */
g_object_set (object, pfd->glib_propname, value, NULL); g_object_set (object, pfd->glib_propname, value, NULL);
} else if (!strcmp (pfd->glib_propname, NM_DEVICE_STATISTICS_REFRESH_RATE_MS)) {
g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32));
/* the same here */
g_object_set (object, pfd->glib_propname, (guint) g_variant_get_uint32 (value), NULL);
} else { } else {
g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)); g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN));
/* the same here */ /* the same here */
@@ -5049,6 +5055,15 @@ prop_filter (GDBusConnection *connection,
} else } else
return message; return message;
interface_type = NMDBUS_TYPE_DEVICE_SKELETON; interface_type = NMDBUS_TYPE_DEVICE_SKELETON;
} else if (!strcmp (propiface, NM_DBUS_INTERFACE_DEVICE_STATISTICS)) {
if (!strcmp (propname, "RefreshRateMs")) {
glib_propname = NM_DEVICE_STATISTICS_REFRESH_RATE_MS;
permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS;
audit_op = NM_AUDIT_OP_STATISTICS;
expected_type = G_VARIANT_TYPE ("u");
} else
return message;
interface_type = NMDBUS_TYPE_DEVICE_SKELETON;
} else } else
return message; return message;

View File

@@ -1476,6 +1476,15 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
nl_info_data = li[IFLA_INFO_DATA]; nl_info_data = li[IFLA_INFO_DATA];
} }
if (tb[IFLA_STATS64]) {
struct rtnl_link_stats64 *stats = nla_data (tb[IFLA_STATS64]);
obj->link.rx_packets = stats->rx_packets;
obj->link.rx_bytes = stats->rx_bytes;
obj->link.tx_packets = stats->tx_packets;
obj->link.tx_bytes = stats->tx_bytes;
}
obj->link.n_ifi_flags = ifi->ifi_flags; obj->link.n_ifi_flags = ifi->ifi_flags;
obj->link.connected = NM_FLAGS_HAS (obj->link.n_ifi_flags, IFF_LOWER_UP); obj->link.connected = NM_FLAGS_HAS (obj->link.n_ifi_flags, IFF_LOWER_UP);
obj->link.arptype = ifi->ifi_type; obj->link.arptype = ifi->ifi_type;
@@ -1568,7 +1577,8 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
&& ( lnk_data_complete_from_cache && ( lnk_data_complete_from_cache
|| address_complete_from_cache || address_complete_from_cache
|| !af_inet6_token_valid || !af_inet6_token_valid
|| !af_inet6_addr_gen_mode_valid)) { || !af_inet6_addr_gen_mode_valid
|| !tb[IFLA_STATS64])) {
_lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached); _lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached);
if (link_cached) { if (link_cached) {
if ( lnk_data_complete_from_cache if ( lnk_data_complete_from_cache
@@ -1591,6 +1601,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
obj->link.inet6_token = link_cached->link.inet6_token; obj->link.inet6_token = link_cached->link.inet6_token;
if (!af_inet6_addr_gen_mode_valid) if (!af_inet6_addr_gen_mode_valid)
obj->link.inet6_addr_gen_mode_inv = link_cached->link.inet6_addr_gen_mode_inv; obj->link.inet6_addr_gen_mode_inv = link_cached->link.inet6_addr_gen_mode_inv;
if (!tb[IFLA_STATS64]) {
obj->link.rx_packets = link_cached->link.rx_packets;
obj->link.rx_bytes = link_cached->link.rx_bytes;
obj->link.tx_packets = link_cached->link.tx_packets;
obj->link.tx_bytes = link_cached->link.tx_bytes;
}
} }
} }
@@ -3732,6 +3748,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
case RTM_NEWLINK: case RTM_NEWLINK:
case RTM_NEWADDR: case RTM_NEWADDR:
case RTM_NEWROUTE: case RTM_NEWROUTE:
case RTM_GETLINK:
cache_op = nmp_cache_update_netlink (priv->cache, obj, &obj_cache, &was_visible, cache_pre_hook, platform); cache_op = nmp_cache_update_netlink (priv->cache, obj, &obj_cache, &was_visible, cache_pre_hook, platform);
cache_post (platform, msghdr, cache_op, obj, obj_cache); cache_post (platform, msghdr, cache_op, obj, obj_cache);

View File

@@ -3115,6 +3115,8 @@ nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len)
"%s%s" /* addr */ "%s%s" /* addr */
"%s%s" /* inet6_token */ "%s%s" /* inet6_token */
"%s%s" /* driver */ "%s%s" /* driver */
" rx:%"G_GUINT64_FORMAT",%"G_GUINT64_FORMAT
" tx:%"G_GUINT64_FORMAT",%"G_GUINT64_FORMAT
, ,
link->ifindex, link->ifindex,
link->name, link->name,
@@ -3133,7 +3135,9 @@ nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len)
link->inet6_token.id ? " inet6token " : "", link->inet6_token.id ? " inet6token " : "",
link->inet6_token.id ? nm_utils_inet6_interface_identifier_to_token (link->inet6_token, str_inet6_token) : "", link->inet6_token.id ? nm_utils_inet6_interface_identifier_to_token (link->inet6_token, str_inet6_token) : "",
link->driver ? " driver " : "", link->driver ? " driver " : "",
link->driver ? link->driver : ""); link->driver ? link->driver : "",
link->rx_packets, link->rx_bytes,
link->tx_packets, link->tx_bytes);
g_string_free (str_flags, TRUE); g_string_free (str_flags, TRUE);
return buf; return buf;
} }
@@ -3794,6 +3798,10 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b)
if (a->addr.len) if (a->addr.len)
_CMP_FIELD_MEMCMP_LEN (a, b, addr.data, a->addr.len); _CMP_FIELD_MEMCMP_LEN (a, b, addr.data, a->addr.len);
_CMP_FIELD_MEMCMP (a, b, inet6_token); _CMP_FIELD_MEMCMP (a, b, inet6_token);
_CMP_FIELD (a, b, rx_packets);
_CMP_FIELD (a, b, rx_bytes);
_CMP_FIELD (a, b, tx_packets);
_CMP_FIELD (a, b, tx_bytes);
return 0; return 0;
} }

View File

@@ -156,6 +156,12 @@ struct _NMPlatformLink {
* initialized with memset(0) has and unset value.*/ * initialized with memset(0) has and unset value.*/
guint8 inet6_addr_gen_mode_inv; guint8 inet6_addr_gen_mode_inv;
/* Statistics */
guint64 rx_packets;
guint64 rx_bytes;
guint64 tx_packets;
guint64 tx_bytes;
/* @connected is mostly identical to (@n_ifi_flags & IFF_UP). Except for bridge/bond masters, /* @connected is mostly identical to (@n_ifi_flags & IFF_UP). Except for bridge/bond masters,
* where we coerce the link as disconnect if it has no slaves. */ * where we coerce the link as disconnect if it has no slaves. */
bool connected:1; bool connected:1;

View File

@@ -567,7 +567,7 @@ test_internal (void)
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL)); g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL));
g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex)); g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
accept_signal (link_changed); accept_signals (link_changed, 1, 2);
g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex)); g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex)); g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));