diff options
author | Thomas Haller <thaller@redhat.com> | 2016-08-17 16:13:16 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2016-08-17 16:13:16 +0200 |
commit | 844345eddde7362318df65fa2d788e11c9fa9f0e (patch) | |
tree | 2f6f87a0b261d9343e7f3dcc1eef16d423eafa9f | |
parent | 2cb18efaea0b0fd90c4633c2c0ff00864fad18b4 (diff) | |
parent | fbbebc21230b707551b0bb7dc920368059644cdc (diff) |
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
-rw-r--r-- | clients/cli/general.c | 2 | ||||
-rw-r--r-- | docs/api/Makefile.am | 1 | ||||
-rw-r--r-- | docs/api/network-manager-docs.xml | 1 | ||||
-rw-r--r-- | introspection/Makefile.am | 6 | ||||
-rw-r--r-- | introspection/nm-device-statistics.xml | 37 | ||||
-rw-r--r-- | libnm-core/nm-dbus-interface.h | 1 | ||||
-rw-r--r-- | libnm-glib/nm-client.c | 2 | ||||
-rw-r--r-- | libnm-glib/nm-client.h | 5 | ||||
-rw-r--r-- | libnm/nm-client.h | 5 | ||||
-rw-r--r-- | libnm/nm-manager.c | 2 | ||||
-rw-r--r-- | policy/org.freedesktop.NetworkManager.policy.in.in | 9 | ||||
-rw-r--r-- | shared/nm-common-macros.h | 1 | ||||
-rw-r--r-- | src/devices/nm-device.c | 171 | ||||
-rw-r--r-- | src/devices/nm-device.h | 4 | ||||
-rw-r--r-- | src/nm-audit-manager.h | 1 | ||||
-rw-r--r-- | src/nm-exported-object.c | 18 | ||||
-rw-r--r-- | src/nm-manager.c | 15 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 19 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 10 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 6 | ||||
-rw-r--r-- | src/platform/tests/test-link.c | 2 |
21 files changed, 304 insertions, 14 deletions
diff --git a/clients/cli/general.c b/clients/cli/general.c index 50e5eeb98c..ccf2292af8 100644 --- a/clients/cli/general.c +++ b/clients/cli/general.c @@ -439,6 +439,8 @@ permission_to_string (NMClientPermission perm) return NM_AUTH_PERMISSION_RELOAD; case NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK: return NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK; + case NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS: + return NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS; default: return _("unknown"); } diff --git a/docs/api/Makefile.am b/docs/api/Makefile.am index 5aafc26248..afe5d3847d 100644 --- a/docs/api/Makefile.am +++ b/docs/api/Makefile.am @@ -73,6 +73,7 @@ content_files = \ $(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-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-vpn-dbus-types.xml \ $(top_builddir)/man/nmcli.xml \ diff --git a/docs/api/network-manager-docs.xml b/docs/api/network-manager-docs.xml index 722e33fd19..bb5ab00496 100644 --- a/docs/api/network-manager-docs.xml +++ b/docs/api/network-manager-docs.xml @@ -98,6 +98,7 @@ <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-secret-agent-org.freedesktop.NetworkManager.SecretAgent.xml"/> + <xi:include href="../../introspection/nmdbus-device-statistics-org.freedesktop.NetworkManager.Device.Statistics.xml"/> </section> <section id="dbus-types"> <title>Types</title> diff --git a/introspection/Makefile.am b/introspection/Makefile.am index d4762637a0..27b54e5d04 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 0000000000..bdb19c89ce --- /dev/null +++ b/introspection/nm-device-statistics.xml @@ -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> diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index c7ce110029..e5b1b3d6b8 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/libnm-glib/nm-client.c b/libnm-glib/nm-client.c index a78c601a19..f0ce64bc31 100644 --- a/libnm-glib/nm-client.c +++ b/libnm-glib/nm-client.c @@ -240,6 +240,8 @@ nm_permission_to_client (const char *nm) return NM_CLIENT_PERMISSION_RELOAD; else if (!strcmp (nm, NM_AUTH_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; } diff --git a/libnm-glib/nm-client.h b/libnm-glib/nm-client.h index a5cfcca0f8..f10b6e54b4 100644 --- a/libnm-glib/nm-client.h +++ b/libnm-glib/nm-client.h @@ -89,6 +89,8 @@ G_BEGIN_DECLS * @NM_CLIENT_PERMISSION_RELOAD: controls access to Reload. * persistent hostname can be changed * @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 * * #NMClientPermission values indicate various permissions that NetworkManager @@ -110,8 +112,9 @@ typedef enum { NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS = 12, NM_CLIENT_PERMISSION_RELOAD = 13, NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK = 14, + NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS = 15, - NM_CLIENT_PERMISSION_LAST = 14, + NM_CLIENT_PERMISSION_LAST = 15, } NMClientPermission; /** diff --git a/libnm/nm-client.h b/libnm/nm-client.h index e2a18b6172..5358ded4a0 100644 --- a/libnm/nm-client.h +++ b/libnm/nm-client.h @@ -98,6 +98,8 @@ G_BEGIN_DECLS * DNS configuration * @NM_CLIENT_PERMISSION_RELOAD: controls access to Reload. * @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 * * #NMClientPermission values indicate various permissions that NetworkManager @@ -119,8 +121,9 @@ typedef enum { NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS = 12, NM_CLIENT_PERMISSION_RELOAD = 13, NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK = 14, + NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS = 15, - NM_CLIENT_PERMISSION_LAST = 14, + NM_CLIENT_PERMISSION_LAST = 15, } NMClientPermission; /** diff --git a/libnm/nm-manager.c b/libnm/nm-manager.c index 4156f651bf..c3d0c51db0 100644 --- a/libnm/nm-manager.c +++ b/libnm/nm-manager.c @@ -234,6 +234,8 @@ nm_permission_to_client (const char *nm) return NM_CLIENT_PERMISSION_RELOAD; else if (!strcmp (nm, NM_AUTH_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; } diff --git a/policy/org.freedesktop.NetworkManager.policy.in.in b/policy/org.freedesktop.NetworkManager.policy.in.in index e0a147a107..7de32f6624 100644 --- a/policy/org.freedesktop.NetworkManager.policy.in.in +++ b/policy/org.freedesktop.NetworkManager.policy.in.in @@ -142,5 +142,14 @@ </defaults> </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> diff --git a/shared/nm-common-macros.h b/shared/nm-common-macros.h index 627d72abf6..6e0769cca4 100644 --- a/shared/nm-common-macros.h +++ b/shared/nm-common-macros.h @@ -38,6 +38,7 @@ #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_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_PERMANENT "permanent" diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 177080d9c5..7e41e9e743 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -71,6 +71,7 @@ _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 +139,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 +411,14 @@ typedef struct _NMDevicePrivate { NMLldpListener *lldp_listener; guint check_delete_unrealized_id; + + struct { + guint timeout_id; + guint refresh_rate_ms; + guint64 tx_bytes; + guint64 rx_bytes; + } stats; + } NMDevicePrivate; 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); } +/*****************************************************************************/ + +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 get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) { @@ -1712,6 +1826,9 @@ device_link_changed (NMDevice *self) _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); nm_device_update_hw_address (self); got_hw_addr = (!had_hw_addr && priv->hw_addr); @@ -1840,6 +1957,8 @@ device_ip_link_changed (NMDevice *self) if (!pllink) return G_SOURCE_REMOVE; + _stats_update_counters_from_pllink (self, pllink); + 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'", priv->ifindex, nm_device_get_ip_ifindex (self), @@ -1850,6 +1969,7 @@ device_ip_link_changed (NMDevice *self) _notify (self, PROP_IP_IFACE); nm_device_update_dynamic_ip_setup (self); } + return G_SOURCE_REMOVE; } @@ -1955,6 +2075,8 @@ nm_device_realize_start (NMDevice *self, gboolean *out_compatible, GError **error) { + NMPlatformLink plink_copy; + NM_SET_OUT (out_compatible, TRUE); if (plink) { @@ -1969,6 +2091,10 @@ nm_device_realize_start (NMDevice *self, return FALSE; } + if (plink) { + plink_copy = *plink; + plink = &plink_copy; + } realize_start_setup (self, plink); return TRUE; @@ -2102,6 +2228,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink) static guint32 id = 0; NMDeviceCapabilities capabilities = 0; NMConfig *config; + guint real_rate; g_return_if_fail (NM_IS_DEVICE (self)); @@ -2125,6 +2252,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink) if (plink) { g_return_if_fail (link_type_compatible (self, plink->type, NULL, NULL)); update_device_from_platform_link (self, plink); + _stats_update_counters_from_pllink (self, plink); } if (priv->ifindex > 0) { @@ -2193,6 +2321,11 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink) 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); /* 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); } + nm_clear_g_source (&priv->stats.timeout_id); + _stats_update_counters (self, 0, 0); + priv->hw_addr_type = HW_ADDR_TYPE_UNSET; g_clear_pointer (&priv->hw_addr_perm, g_free); _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->stats.timeout_id); + link_disconnect_action_cancel (self); if (priv->settings) { @@ -12237,6 +12375,9 @@ set_property (GObject *object, guint prop_id, /* construct only */ priv->hw_addr_perm = g_value_dup_string (value); break; + case PROP_REFRESH_RATE_MS: + _stats_set_refresh_rate (self, g_value_get_uint (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -12399,6 +12540,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->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: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -12649,6 +12799,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 */ @@ -12719,4 +12886,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 6a4f22a5f4..433448565d 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 ()) diff --git a/src/nm-audit-manager.h b/src/nm-audit-manager.h index a14da5bbb9..2d44c2ca52 100644 --- a/src/nm-audit-manager.h +++ b/src/nm-audit-manager.h @@ -57,6 +57,7 @@ typedef struct { #define NM_AUDIT_OP_SLEEP_CONTROL "sleep-control" #define NM_AUDIT_OP_NET_CONTROL "networking-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_DISCONNECT "device-disconnect" diff --git a/src/nm-exported-object.c b/src/nm-exported-object.c index b313ff6c07..c4dbab8715 100644 --- a/src/nm-exported-object.c +++ b/src/nm-exported-object.c @@ -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 (g_type_is_a (dbus_skeleton_type, G_TYPE_DBUS_INTERFACE_SKELETON)); - classinfo = g_slice_new (NMExportedObjectClassInfo); - classinfo->skeleton_types = NULL; - 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 = g_type_get_qdata (G_TYPE_FROM_CLASS (object_class), + nm_exported_object_class_info_quark ()); + if (!classinfo) { + classinfo = g_slice_new (NMExportedObjectClassInfo); + classinfo->skeleton_types = NULL; + 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, 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); } diff --git a/src/nm-manager.c b/src/nm-manager.c index 88723e0298..89dc736044 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -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_RELOAD); 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_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_RELOAD, 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 @@ -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 * on the skeleton interface, but as it is now, the result is the same. */ 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 { g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)); /* the same here */ @@ -5049,6 +5055,15 @@ prop_filter (GDBusConnection *connection, } else return message; 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 return message; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index deb6c5f977..98c4e461ab 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -1476,6 +1476,15 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr 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.connected = NM_FLAGS_HAS (obj->link.n_ifi_flags, IFF_LOWER_UP); 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 || address_complete_from_cache || !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); if (link_cached) { 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; if (!af_inet6_addr_gen_mode_valid) 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_NEWADDR: case RTM_NEWROUTE: + case RTM_GETLINK: 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); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 75c85b9255..9dace69984 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -3115,6 +3115,8 @@ nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len) "%s%s" /* addr */ "%s%s" /* inet6_token */ "%s%s" /* driver */ + " rx:%"G_GUINT64_FORMAT",%"G_GUINT64_FORMAT + " tx:%"G_GUINT64_FORMAT",%"G_GUINT64_FORMAT , link->ifindex, 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 ? nm_utils_inet6_interface_identifier_to_token (link->inet6_token, str_inet6_token) : "", 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); return buf; } @@ -3794,6 +3798,10 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b) if (a->addr.len) _CMP_FIELD_MEMCMP_LEN (a, b, addr.data, a->addr.len); _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; } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index c419855a98..fc6965e904 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -156,6 +156,12 @@ struct _NMPlatformLink { * initialized with memset(0) has and unset value.*/ 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, * where we coerce the link as disconnect if it has no slaves. */ bool connected:1; diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index e0870df561..9bf8aca831 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -567,7 +567,7 @@ test_internal (void) 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_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_is_up (NM_PLATFORM_GET, ifindex)); g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); |