diff --git a/introspection/Makefile.am b/introspection/Makefile.am
index d4762637a..27b54e5d0 100644
--- a/introspection/Makefile.am
+++ b/introspection/Makefile.am
@@ -43,6 +43,8 @@ nodist_libnmdbus_la_SOURCES = \
nmdbus-device-modem.h \
nmdbus-device-olpc-mesh.c \
nmdbus-device-olpc-mesh.h \
+ nmdbus-device-statistics.c \
+ nmdbus-device-statistics.h \
nmdbus-device-team.c \
nmdbus-device-team.h \
nmdbus-device-tun.c \
@@ -114,7 +116,8 @@ DBUS_INTERFACE_DOCS = \
nmdbus-device-veth-org.freedesktop.NetworkManager.Device.Veth.xml \
nmdbus-settings-org.freedesktop.NetworkManager.Settings.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
$(1): $(patsubst nmdbus-%.c,nm-%.xml,$(1))
@@ -154,6 +157,7 @@ EXTRA_DIST = \
nm-device-macvlan.xml \
nm-device-modem.xml \
nm-device-olpc-mesh.xml \
+ nm-device-statistics.xml \
nm-device-team.xml \
nm-device-tun.xml \
nm-device-veth.xml \
diff --git a/introspection/nm-device-statistics.xml b/introspection/nm-device-statistics.xml
new file mode 100644
index 000000000..5d23bf306
--- /dev/null
+++ b/introspection/nm-device-statistics.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index c7ce11002..e5b1b3d6b 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -68,6 +68,7 @@
#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_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_PATH_SETTINGS "/org/freedesktop/NetworkManager/Settings"
diff --git a/src/Makefile.am b/src/Makefile.am
index c460caff6..35bcf93ff 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -331,6 +331,8 @@ libNetworkManager_la_SOURCES = \
devices/nm-device-generic.h \
devices/nm-device-logging.h \
devices/nm-device-private.h \
+ devices/nm-device-statistics.c \
+ devices/nm-device-statistics.h \
\
dhcp-manager/nm-dhcp-client.c \
dhcp-manager/nm-dhcp-client.h \
diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h
index 7381fd930..58216e175 100644
--- a/src/devices/nm-device-private.h
+++ b/src/devices/nm-device-private.h
@@ -114,6 +114,9 @@ void nm_device_ip_method_failed (NMDevice *self, int family, NMDeviceStateReason
gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value);
+void nm_device_set_tx_bytes (NMDevice *self, guint64 tx_bytes);
+void nm_device_set_rx_bytes (NMDevice *self, guint64 rx_bytes);
+
#define NM_DEVICE_CLASS_DECLARE_TYPES(klass, conn_type, ...) \
NM_DEVICE_CLASS (klass)->connection_type = conn_type; \
{ \
diff --git a/src/devices/nm-device-statistics.c b/src/devices/nm-device-statistics.c
new file mode 100644
index 000000000..b5d4197cf
--- /dev/null
+++ b/src/devices/nm-device-statistics.c
@@ -0,0 +1,99 @@
+/* -*- 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 (C) 2016 Canonical Ltd
+ *
+ */
+
+#include "nm-default.h"
+
+#include
+
+#include "nm-device-statistics.h"
+#include "nm-device-private.h"
+#include "nm-utils.h"
+#include "nm-platform.h"
+
+#define _NMLOG_DOMAIN LOGD_DEVICE
+#define _NMLOG(level, ...) \
+ nm_log_obj ((level), _NMLOG_DOMAIN, (self->device), "device-stats", \
+ "(%s): " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+ nm_device_get_iface (self->device) ?: "(none)" \
+ _NM_UTILS_MACRO_REST(__VA_ARGS__))
+
+struct _NMDeviceStatistics {
+ NMDevice *device;
+ guint stats_update_id;
+};
+
+static gboolean
+update_stats (gpointer user_data)
+{
+ NMDeviceStatistics *self = user_data;
+ guint64 rx_packets;
+ guint64 rx_bytes;
+ guint64 tx_packets;
+ guint64 tx_bytes;
+ int ifindex;
+
+ ifindex = nm_device_get_ip_ifindex (self->device);
+
+ if (nm_platform_link_get_stats (NM_PLATFORM_GET, ifindex,
+ &rx_packets, &rx_bytes,
+ &tx_packets, &tx_bytes)) {
+ _LOGT ("{RX} %"PRIu64" packets %"PRIu64" bytes {TX} %"PRIu64" packets %"PRIu64" bytes",
+ rx_packets, rx_bytes, tx_packets, tx_bytes);
+
+ nm_device_set_tx_bytes (self->device, tx_bytes);
+ nm_device_set_rx_bytes (self->device, rx_bytes);
+ } else {
+ _LOGE ("error no stats available");
+ }
+
+ /* Keep polling */
+ nm_platform_link_refresh (NM_PLATFORM_GET, ifindex);
+
+ return TRUE;
+}
+
+/********************************************/
+
+NMDeviceStatistics *
+nm_device_statistics_new (NMDevice *device, unsigned rate_ms)
+{
+ NMDeviceStatistics *self;
+
+ self = g_malloc0 (sizeof (*self));
+ self->device = device;
+
+ self->stats_update_id = g_timeout_add (rate_ms, update_stats, self);
+
+ return self;
+}
+
+void
+nm_device_statistics_unref (NMDeviceStatistics *self)
+{
+ g_source_remove (self->stats_update_id);
+ g_free (self);
+}
+
+void
+nm_device_statistics_change_rate (NMDeviceStatistics *self, unsigned rate_ms)
+{
+ g_source_remove (self->stats_update_id);
+
+ self->stats_update_id = g_timeout_add (rate_ms, update_stats, self);
+}
diff --git a/src/devices/nm-device-statistics.h b/src/devices/nm-device-statistics.h
new file mode 100644
index 000000000..17ff19f48
--- /dev/null
+++ b/src/devices/nm-device-statistics.h
@@ -0,0 +1,31 @@
+/* -*- 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 (C) 2016 Canonical Ltd
+ */
+
+#ifndef __NETWORKMANAGER_DEVICE_STATISTICS_H__
+#define __NETWORKMANAGER_DEVICE_STATISTICS_H__
+
+typedef struct _NMDeviceStatistics NMDeviceStatistics;
+
+NMDeviceStatistics *
+nm_device_statistics_new (NMDevice *device, unsigned rate_ms);
+
+void nm_device_statistics_unref (NMDeviceStatistics *self);
+
+void nm_device_statistics_change_rate (NMDeviceStatistics *self, unsigned rate_ms);
+
+#endif /* __NETWORKMANAGER_DEVICE_STATISTICS_H__ */
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 9c7319f03..72ed5e911 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -66,11 +66,13 @@
#include "sd-ipv4ll.h"
#include "nm-audit-manager.h"
#include "nm-arping-manager.h"
+#include "nm-device-statistics.h"
#include "nm-device-logging.h"
_LOG_DECLARE_SELF (NMDevice);
#include "nmdbus-device.h"
+#include "nmdbus-device-statistics.h"
G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_EXPORTED_OBJECT)
@@ -138,6 +140,9 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDevice,
PROP_LLDP_NEIGHBORS,
PROP_REAL,
PROP_SLAVES,
+ PROP_REFRESH_RATE_MS,
+ PROP_TX_BYTES,
+ PROP_RX_BYTES,
);
#define DEFAULT_AUTOCONNECT TRUE
@@ -407,6 +412,13 @@ typedef struct _NMDevicePrivate {
NMLldpListener *lldp_listener;
guint check_delete_unrealized_id;
+
+ guint refresh_rate_ms;
+ guint64 tx_bytes;
+ guint64 rx_bytes;
+
+ NMDeviceStatistics *statistics;
+
} NMDevicePrivate;
static gboolean nm_device_set_ip4_config (NMDevice *self,
@@ -769,6 +781,36 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
g_free (old_ip_iface);
}
+void
+nm_device_set_tx_bytes (NMDevice *self, guint64 tx_bytes)
+{
+ NMDevicePrivate *priv;
+
+ g_return_if_fail (NM_IS_DEVICE (self));
+
+ priv = NM_DEVICE_GET_PRIVATE (self);
+ if (tx_bytes == priv->tx_bytes)
+ return;
+
+ priv->tx_bytes = tx_bytes;
+ _notify (self, PROP_TX_BYTES);
+}
+
+void
+nm_device_set_rx_bytes (NMDevice *self, guint64 rx_bytes)
+{
+ NMDevicePrivate *priv;
+
+ g_return_if_fail (NM_IS_DEVICE (self));
+
+ priv = NM_DEVICE_GET_PRIVATE (self);
+ if (rx_bytes == priv->rx_bytes)
+ return;
+
+ priv->rx_bytes = rx_bytes;
+ _notify (self, PROP_RX_BYTES);
+}
+
static gboolean
get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid)
{
@@ -2199,6 +2241,11 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
priv->carrier = TRUE;
}
+ if (priv->refresh_rate_ms && !priv->statistics) {
+ priv->statistics = nm_device_statistics_new (self,
+ priv->refresh_rate_ms);
+ }
+
klass->realize_start_notify (self, plink);
/* Do not manage externally created software devices until they are IFF_UP
@@ -2370,6 +2417,14 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
g_clear_pointer (&priv->physical_port_id, g_free);
_notify (self, PROP_PHYSICAL_PORT_ID);
}
+ if (priv->statistics) {
+ nm_device_statistics_unref (priv->statistics);
+ priv->statistics = NULL;
+ priv->tx_bytes = 0;
+ priv->tx_bytes = 0;
+ _notify (self, PROP_TX_BYTES);
+ _notify (self, PROP_RX_BYTES);
+ }
priv->hw_addr_type = HW_ADDR_TYPE_UNSET;
g_clear_pointer (&priv->hw_addr_perm, g_free);
@@ -11963,6 +12018,11 @@ nm_device_init (NMDevice *self)
priv->v4_commit_first_time = TRUE;
priv->v6_commit_first_time = TRUE;
+
+ priv->refresh_rate_ms = 0;
+ priv->tx_bytes = 0;
+ priv->rx_bytes = 0;
+ priv->statistics = NULL;
}
static GObject*
@@ -12111,6 +12171,11 @@ dispose (GObject *object)
g_clear_object (&priv->lldp_listener);
}
+ if (priv->statistics) {
+ nm_device_statistics_unref (priv->statistics);
+ priv->statistics = NULL;
+ }
+
G_OBJECT_CLASS (nm_device_parent_class)->dispose (object);
if (nm_clear_g_source (&priv->queued_state.id)) {
@@ -12243,6 +12308,28 @@ set_property (GObject *object, guint prop_id,
/* construct only */
priv->hw_addr_perm = g_value_dup_string (value);
break;
+ case PROP_REFRESH_RATE_MS: {
+ guint refresh_rate_ms;
+
+ refresh_rate_ms = g_value_get_uint (value);
+ if (priv->refresh_rate_ms == refresh_rate_ms)
+ break;
+
+ priv->refresh_rate_ms = refresh_rate_ms;
+ _LOGI (LOGD_DEVICE, "statistics refresh rate set to %u ms", priv->refresh_rate_ms);
+
+ if (priv->refresh_rate_ms) {
+ if (priv->statistics)
+ nm_device_statistics_change_rate (priv->statistics, priv->refresh_rate_ms);
+ else
+ priv->statistics =
+ nm_device_statistics_new (self, priv->refresh_rate_ms);
+ } else {
+ nm_device_statistics_unref (priv->statistics);
+ priv->statistics = NULL;
+ }
+ break;
+ }
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -12405,6 +12492,15 @@ get_property (GObject *object, guint prop_id,
g_value_take_boxed (value, slave_list);
break;
}
+ case PROP_REFRESH_RATE_MS:
+ g_value_set_uint (value, priv->refresh_rate_ms);
+ break;
+ case PROP_TX_BYTES:
+ g_value_set_uint64 (value, priv->tx_bytes);
+ break;
+ case PROP_RX_BYTES:
+ g_value_set_uint64 (value, priv->rx_bytes);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -12655,6 +12751,23 @@ nm_device_class_init (NMDeviceClass *klass)
G_PARAM_READABLE |
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);
/* Signals */
@@ -12725,4 +12838,8 @@ nm_device_class_init (NMDeviceClass *klass)
"Disconnect", impl_device_disconnect,
"Delete", impl_device_delete,
NULL);
+
+ nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
+ NMDBUS_TYPE_DEVICE_STATISTICS_SKELETON,
+ NULL);
}
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 6a4f22a5f..433448565 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -88,6 +88,10 @@
#define NM_DEVICE_STATE_CHANGED "state-changed"
#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
#define NM_TYPE_DEVICE (nm_device_get_type ())