Merge ~alfonsosanchezbeato/network-manager/+git/ubuntu:touch-vivid-add-statitics into network-manager:touch-vivid

Proposed by Alfonso Sanchez-Beato
Status: Merged
Merged at revision: 92ac043cd375662fa7546ccdd0cc7aecbc275929
Proposed branch: ~alfonsosanchezbeato/network-manager/+git/ubuntu:touch-vivid-add-statitics
Merge into: network-manager:touch-vivid
Diff against target: 856 lines (+842/-0)
2 files modified
debian/patches/Add-statistics-interface.patch (+841/-0)
debian/patches/series (+1/-0)
Reviewer Review Type Date Requested Status
Tony Espy Approve
Review via email: mp+296433@code.launchpad.net

Commit message

ubuntu: Add statistics interface

Description of the change

ubuntu: Add statistics interface

To post a comment you must log in.
Revision history for this message
Tony Espy (awe) :
review: Needs Fixing
Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote :

Branch refreshed after addressing comments.

Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote :

Some compilation warning fixed.

Revision history for this message
Tony Espy (awe) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/debian/patches/Add-statistics-interface.patch b/debian/patches/Add-statistics-interface.patch
0new file mode 1006440new file mode 100644
index 0000000..2c3dcd2
--- /dev/null
+++ b/debian/patches/Add-statistics-interface.patch
@@ -0,0 +1,841 @@
1From: Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
2Date: Fri, 3 Jun 2016 14:55:22 +0200
3Subject: Add statistics interface
4
5---
6 introspection/Makefile.am | 6 +-
7 introspection/nm-device-statistics.xml | 43 ++++
8 libnm-core/nm-dbus-interface.h | 1 +
9 src/Makefile.am | 2 +
10 src/devices/nm-device-private.h | 3 +
11 src/devices/nm-device-statistics.c | 407 +++++++++++++++++++++++++++++++++
12 src/devices/nm-device-statistics.h | 33 +++
13 src/devices/nm-device.c | 102 ++++++++-
14 src/devices/nm-device.h | 4 +
15 src/nm-exported-object.c | 18 +-
16 src/nm-types.h | 1 +
17 11 files changed, 610 insertions(+), 10 deletions(-)
18 create mode 100644 introspection/nm-device-statistics.xml
19 create mode 100644 src/devices/nm-device-statistics.c
20 create mode 100644 src/devices/nm-device-statistics.h
21
22diff --git a/introspection/Makefile.am b/introspection/Makefile.am
23index 3a62793..f72703d 100644
24--- a/introspection/Makefile.am
25+++ b/introspection/Makefile.am
26@@ -41,6 +41,8 @@ nodist_libnmdbus_la_SOURCES = \
27 nmdbus-device-modem.h \
28 nmdbus-device-olpc-mesh.c \
29 nmdbus-device-olpc-mesh.h \
30+ nmdbus-device-statistics.c \
31+ nmdbus-device-statistics.h \
32 nmdbus-device-team.c \
33 nmdbus-device-team.h \
34 nmdbus-device-tun.c \
35@@ -111,7 +113,8 @@ DBUS_INTERFACE_DOCS = \
36 nmdbus-device-veth-org.freedesktop.NetworkManager.Device.Veth.xml \
37 nmdbus-settings-org.freedesktop.NetworkManager.Settings.xml \
38 nmdbus-device-ethernet-org.freedesktop.NetworkManager.Device.Wired.xml \
39- nmdbus-ip4-config-org.freedesktop.NetworkManager.IP4Config.xml
40+ nmdbus-ip4-config-org.freedesktop.NetworkManager.IP4Config.xml \
41+ nmdbus-device-statistics-org.freedesktop.NetworkManager.Device.Statistics.xml
42
43 define _make_nmdbus_rule
44 $(1): $(patsubst nmdbus-%.c,nm-%.xml,$(1))
45@@ -150,6 +153,7 @@ EXTRA_DIST = \
46 nm-device-macvlan.xml \
47 nm-device-modem.xml \
48 nm-device-olpc-mesh.xml \
49+ nm-device-statistics.xml \
50 nm-device-team.xml \
51 nm-device-tun.xml \
52 nm-device-veth.xml \
53diff --git a/introspection/nm-device-statistics.xml b/introspection/nm-device-statistics.xml
54new file mode 100644
55index 0000000..08a700e
56--- /dev/null
57+++ b/introspection/nm-device-statistics.xml
58@@ -0,0 +1,43 @@
59+<?xml version="1.0" encoding="UTF-8"?>
60+<node name="/">
61+ <interface name="org.freedesktop.NetworkManager.Device.Statistics">
62+
63+ <!--
64+ RefreshRateMs:
65+
66+ Rate of change of the rest of properties of this interface. If zero, the
67+ properties do not change. Othewise, the properties are refreshed each
68+ RefreshRateMs milliseconds in case the underlaying counter has changed
69+ too.
70+
71+ Returns: Unsigned 32-bit integer
72+ -->
73+ <property name="RefreshRateMs" type="u" access="readwrite"/>
74+
75+ <!--
76+ TxBytes:
77+
78+ Number of transmitted bytes
79+
80+ Returns: Unsigned 64-bit integer
81+ -->
82+ <property name="TxBytes" type="t" access="read"/>
83+
84+ <!--
85+ RxBytes:
86+
87+ Number of received bytes
88+
89+ Returns: Unsigned 64-bit integer
90+ -->
91+ <property name="RxBytes" type="t" access="read"/>
92+
93+ <!--
94+ PropertiesChanged:
95+ @properties: A dictionary mapping property names to variant boxed values
96+ -->
97+ <signal name="PropertiesChanged">
98+ <arg name="properties" type="a{sv}"/>
99+ </signal>
100+ </interface>
101+</node>
102diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
103index f3d7945..6f0fc23 100644
104--- a/libnm-core/nm-dbus-interface.h
105+++ b/libnm-core/nm-dbus-interface.h
106@@ -68,6 +68,7 @@
107 #define NM_DBUS_INTERFACE_DEVICE_VXLAN NM_DBUS_INTERFACE_DEVICE ".Vxlan"
108 #define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre"
109 #define NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL NM_DBUS_INTERFACE_DEVICE ".IPTunnel"
110+#define NM_DBUS_INTERFACE_DEVICE_STATISTICS NM_DBUS_INTERFACE_DEVICE ".Statistics"
111
112 #define NM_DBUS_INTERFACE_SETTINGS "org.freedesktop.NetworkManager.Settings"
113 #define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManager/Settings"
114diff --git a/src/Makefile.am b/src/Makefile.am
115index 49028f1..1b749e3 100644
116--- a/src/Makefile.am
117+++ b/src/Makefile.am
118@@ -286,6 +286,8 @@ libNetworkManager_la_SOURCES = \
119 devices/nm-device-generic.h \
120 devices/nm-device-logging.h \
121 devices/nm-device-private.h \
122+ devices/nm-device-statistics.c \
123+ devices/nm-device-statistics.h \
124 \
125 dhcp-manager/nm-dhcp-client.c \
126 dhcp-manager/nm-dhcp-client.h \
127diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h
128index 602c2c8..f84460a 100644
129--- a/src/devices/nm-device-private.h
130+++ b/src/devices/nm-device-private.h
131@@ -105,6 +105,9 @@ void nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config);
132
133 gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value);
134
135+void nm_device_set_tx_bytes (NMDevice *self, guint64 tx_bytes);
136+void nm_device_set_rx_bytes (NMDevice *self, guint64 rx_bytes);
137+
138 #define NM_DEVICE_CLASS_DECLARE_TYPES(klass, conn_type, ...) \
139 NM_DEVICE_CLASS (klass)->connection_type = conn_type; \
140 { \
141diff --git a/src/devices/nm-device-statistics.c b/src/devices/nm-device-statistics.c
142new file mode 100644
143index 0000000..daf67f1
144--- /dev/null
145+++ b/src/devices/nm-device-statistics.c
146@@ -0,0 +1,407 @@
147+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
148+/* This program is free software; you can redistribute it and/or modify
149+ * it under the terms of the GNU General Public License as published by
150+ * the Free Software Foundation; either version 2, or (at your option)
151+ * any later version.
152+ *
153+ * This program is distributed in the hope that it will be useful,
154+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
155+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
156+ * GNU General Public License for more details.
157+ *
158+ * You should have received a copy of the GNU General Public License along
159+ * with this program; if not, write to the Free Software Foundation, Inc.,
160+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
161+ *
162+ * Copyright (C) 2016 Canonical Ltd
163+ *
164+ */
165+
166+#include "nm-default.h"
167+
168+#include <errno.h>
169+#include <stdio.h>
170+#include <unistd.h>
171+#include <string.h>
172+#include <sys/socket.h>
173+#include <sys/ioctl.h>
174+#include <arpa/inet.h>
175+#include <netinet/ether.h>
176+#include <netinet/icmp6.h>
177+#include <net/if_arp.h>
178+#include <linux/if.h>
179+#include <linux/netlink.h>
180+#include <linux/rtnetlink.h>
181+#include <linux/wireless.h>
182+
183+#include "nm-device-private.h"
184+#include "nm-device-statistics.h"
185+
186+#define _NMLOG_DOMAIN LOGD_DEVICE
187+#define _NMLOG_PREFIX_NAME "device (stats)"
188+#define _NMLOG(level, ...) \
189+ G_STMT_START { \
190+ nm_log ((level), _NMLOG_DOMAIN, \
191+ "%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
192+ _NMLOG_PREFIX_NAME": " \
193+ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
194+ } G_STMT_END
195+
196+struct rtnl_request {
197+ struct nlmsghdr hdr;
198+ struct rtgenmsg msg;
199+};
200+
201+#define RTNL_REQUEST_SIZE (sizeof (struct nlmsghdr) + sizeof (struct rtgenmsg))
202+#define SOCK_RX_BUFF_SIZE 4096
203+
204+struct _NMDeviceStatistics {
205+ NMDevice *device;
206+ char *iface;
207+ GIOChannel *channel;
208+ guint channel_watch;
209+ guint stats_update_id;
210+ gboolean req_pending;
211+ guint32 request_seq;
212+ unsigned char buf[SOCK_RX_BUFF_SIZE];
213+};
214+
215+static const char *
216+type_to_string (uint16_t type)
217+{
218+ switch (type) {
219+ case NLMSG_NOOP:
220+ return "NOOP";
221+ case NLMSG_ERROR:
222+ return "ERROR";
223+ case NLMSG_DONE:
224+ return "DONE";
225+ case NLMSG_OVERRUN:
226+ return "OVERRUN";
227+ case RTM_GETLINK:
228+ return "GETLINK";
229+ case RTM_NEWLINK:
230+ return "NEWLINK";
231+ case RTM_DELLINK:
232+ return "DELLINK";
233+ case RTM_GETADDR:
234+ return "GETADDR";
235+ case RTM_NEWADDR:
236+ return "NEWADDR";
237+ case RTM_DELADDR:
238+ return "DELADDR";
239+ case RTM_GETROUTE:
240+ return "GETROUTE";
241+ case RTM_NEWROUTE:
242+ return "NEWROUTE";
243+ case RTM_DELROUTE:
244+ return "DELROUTE";
245+ case RTM_NEWNDUSEROPT:
246+ return "NEWNDUSEROPT";
247+ default:
248+ return "UNKNOWN";
249+ }
250+}
251+
252+static const char *
253+operstate_to_str (unsigned char operstate)
254+{
255+ switch (operstate) {
256+ case IF_OPER_UNKNOWN:
257+ return "UNKNOWN";
258+ case IF_OPER_NOTPRESENT:
259+ return "NOT-PRESENT";
260+ case IF_OPER_DOWN:
261+ return "DOWN";
262+ case IF_OPER_LOWERLAYERDOWN:
263+ return "LOWER-LAYER-DOWN";
264+ case IF_OPER_TESTING:
265+ return "TESTING";
266+ case IF_OPER_DORMANT:
267+ return "DORMANT";
268+ case IF_OPER_UP:
269+ return "UP";
270+ default:
271+ return "";
272+ }
273+}
274+
275+static gboolean
276+extract_link (struct ifinfomsg *msg, int bytes,
277+ struct ether_addr *address, const char **ifname,
278+ unsigned int *mtu, unsigned char *operstate,
279+ struct rtnl_link_stats *stats)
280+{
281+ struct rtattr *attr;
282+
283+ for (attr = IFLA_RTA (msg); RTA_OK (attr, bytes);
284+ attr = RTA_NEXT (attr, bytes)) {
285+
286+ switch (attr->rta_type) {
287+ case IFLA_ADDRESS:
288+ if (address)
289+ memcpy (address, RTA_DATA (attr), ETH_ALEN);
290+ break;
291+ case IFLA_IFNAME:
292+ if (ifname)
293+ *ifname = RTA_DATA (attr);
294+ break;
295+ case IFLA_MTU:
296+ if (mtu)
297+ *mtu = *(unsigned int *) RTA_DATA (attr);
298+ break;
299+ case IFLA_STATS:
300+ if (stats)
301+ memcpy (stats, RTA_DATA (attr),
302+ sizeof (struct rtnl_link_stats));
303+ break;
304+ case IFLA_OPERSTATE:
305+ if (operstate)
306+ *operstate = *(unsigned char *) RTA_DATA (attr);
307+ break;
308+ case IFLA_LINKMODE:
309+ break;
310+ case IFLA_WIRELESS:
311+ return FALSE;
312+ }
313+ }
314+
315+ return TRUE;
316+}
317+
318+static void
319+process_newlink (NMDeviceStatistics *self, unsigned short type, int index,
320+ unsigned flags, unsigned change, struct ifinfomsg *msg,
321+ int bytes)
322+{
323+ struct ether_addr address = { { 0, 0, 0, 0, 0, 0 } };
324+ struct rtnl_link_stats stats = { 0 };
325+ unsigned char operstate = 0xFF;
326+ const char *ifname = NULL;
327+ unsigned int mtu = 0;
328+ char hw_addr[3 * sizeof (address)];
329+
330+ if (!extract_link (msg, bytes, &address, &ifname, &mtu, &operstate, &stats))
331+ return;
332+
333+ if (g_strcmp0 (ifname, self->iface) != 0)
334+ return;
335+
336+ snprintf(hw_addr, sizeof (hw_addr), "%02X:%02X:%02X:%02X:%02X:%02X",
337+ address.ether_addr_octet[0],
338+ address.ether_addr_octet[1],
339+ address.ether_addr_octet[2],
340+ address.ether_addr_octet[3],
341+ address.ether_addr_octet[4],
342+ address.ether_addr_octet[5]);
343+
344+ if (flags & IFF_SLAVE) {
345+ _LOGD ("%s {newlink} ignoring slave, index %d address %s",
346+ ifname, index, hw_addr);
347+ return;
348+ }
349+
350+ _LOGD ("%s {newlink} index %d address %s mtu %u operstate %u <%s>",
351+ ifname, index, hw_addr, mtu, operstate, operstate_to_str (operstate));
352+ _LOGD ("%s {RX} %u packets %u bytes", ifname,
353+ stats.rx_packets, stats.rx_bytes);
354+ _LOGD ("%s {TX} %u packets %u bytes", ifname,
355+ stats.tx_packets, stats.tx_bytes);
356+
357+ nm_device_set_tx_bytes (self->device, stats.tx_bytes);
358+ nm_device_set_rx_bytes (self->device, stats.rx_bytes);
359+}
360+
361+static void
362+rtnl_newlink (NMDeviceStatistics *self, struct nlmsghdr *hdr)
363+{
364+ struct ifinfomsg *msg = (struct ifinfomsg *) NLMSG_DATA (hdr);
365+
366+ if (hdr->nlmsg_type == IFLA_WIRELESS)
367+ _LOGW ("Obsolete WEXT WiFi driver detected");
368+
369+ process_newlink (self, msg->ifi_type, msg->ifi_index, msg->ifi_flags,
370+ msg->ifi_change, msg, IFA_PAYLOAD (hdr));
371+}
372+
373+static void
374+rtnl_message (NMDeviceStatistics *self, unsigned char *buf, size_t len)
375+{
376+ while (len > 0) {
377+ struct nlmsghdr *hdr = (struct nlmsghdr *) buf;
378+ struct nlmsgerr *err;
379+
380+ if (!NLMSG_OK (hdr, len))
381+ break;
382+
383+ switch (hdr->nlmsg_type) {
384+ case NLMSG_NOOP:
385+ case NLMSG_OVERRUN:
386+ return;
387+ case NLMSG_DONE:
388+ if (hdr->nlmsg_seq == self->request_seq - 1)
389+ self->req_pending = FALSE;
390+ return;
391+ case NLMSG_ERROR:
392+ err = NLMSG_DATA (hdr);
393+ return;
394+ case RTM_NEWLINK:
395+ rtnl_newlink (self, hdr);
396+ break;
397+ case RTM_DELLINK:
398+ case RTM_NEWADDR:
399+ case RTM_DELADDR:
400+ case RTM_NEWROUTE:
401+ case RTM_DELROUTE:
402+ case RTM_NEWNDUSEROPT:
403+ break;
404+ }
405+
406+ len -= hdr->nlmsg_len;
407+ buf += hdr->nlmsg_len;
408+ }
409+}
410+
411+static gboolean
412+netlink_event (GIOChannel *chan, GIOCondition cond, gpointer data)
413+{
414+ struct sockaddr_nl nladdr = { 0 };
415+ socklen_t addr_len = sizeof (nladdr);
416+ ssize_t status;
417+ int fd;
418+ NMDeviceStatistics *self = data;
419+
420+ if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
421+ _LOGE ("netlink socket error %d", errno);
422+ return FALSE;
423+ }
424+
425+ fd = g_io_channel_unix_get_fd (chan);
426+
427+ status = recvfrom (fd, self->buf, sizeof (self->buf), 0,
428+ (struct sockaddr *) &nladdr, &addr_len);
429+ if (status < 0) {
430+ if (errno == EINTR || errno == EAGAIN)
431+ return TRUE;
432+
433+ _LOGE ("error %d on receiving from netlink socket", errno);
434+ return FALSE;
435+ }
436+
437+ /* EOF, remove callback */
438+ if (status == 0)
439+ return FALSE;
440+
441+ /* not sent by kernel, ignore */
442+ if (nladdr.nl_pid != 0)
443+ return TRUE;
444+
445+ rtnl_message (self, self->buf, status);
446+
447+ return TRUE;
448+}
449+
450+static int
451+send_getlink (NMDeviceStatistics *self)
452+{
453+ struct rtnl_request req = { 0 };
454+ struct sockaddr_nl addr = { 0 };
455+ int sk;
456+
457+ req.hdr.nlmsg_len = RTNL_REQUEST_SIZE;
458+ req.hdr.nlmsg_type = RTM_GETLINK;
459+ req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
460+ req.hdr.nlmsg_pid = 0;
461+ req.hdr.nlmsg_seq = self->request_seq++;
462+ req.msg.rtgen_family = AF_UNSPEC;
463+
464+ _LOGD ("Sending %s len %d type %d flags 0x%04x seq %d",
465+ type_to_string (req.hdr.nlmsg_type),
466+ req.hdr.nlmsg_len, req.hdr.nlmsg_type,
467+ req.hdr.nlmsg_flags, req.hdr.nlmsg_seq);
468+
469+ sk = g_io_channel_unix_get_fd(self->channel);
470+
471+ addr.nl_family = AF_NETLINK;
472+
473+ self->req_pending = TRUE;
474+
475+ return sendto (sk, &req, req.hdr.nlmsg_len, 0,
476+ (struct sockaddr *) &addr, sizeof (addr));
477+}
478+
479+static gboolean
480+update_stats (gpointer user_data)
481+{
482+ NMDeviceStatistics *self = user_data;
483+
484+ if (self->req_pending) {
485+ _LOGD ("no response yet for pending netlink request");
486+ return TRUE;
487+ }
488+
489+ send_getlink (self);
490+ return TRUE;
491+}
492+
493+/********************************************/
494+
495+NMDeviceStatistics *
496+nm_device_statistics_create (NMDevice *device, const char *iface, unsigned rate_ms)
497+{
498+ NMDeviceStatistics *self;
499+ struct sockaddr_nl addr = { 0 };
500+ int sk;
501+ GIOChannel *channel = NULL;
502+ guint channel_watch = 0;
503+
504+ self = g_malloc0 (sizeof (*self));
505+
506+ sk = socket (PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
507+ if (sk < 0) {
508+ _LOGE ("Cannot create netlink socket: %d", errno);
509+ goto error;
510+ }
511+
512+ addr.nl_family = AF_NETLINK;
513+ addr.nl_groups = RTMGRP_LINK;
514+
515+ if (bind (sk, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
516+ close (sk);
517+ _LOGE ("Cannot bind to netlink socket: %d", errno);
518+ goto error;
519+ }
520+
521+ channel = g_io_channel_unix_new (sk);
522+
523+ g_io_channel_set_close_on_unref (channel, TRUE);
524+ g_io_channel_set_encoding (channel, NULL, NULL);
525+ g_io_channel_set_buffered (channel, FALSE);
526+
527+ channel_watch =
528+ g_io_add_watch (channel,
529+ G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
530+ netlink_event, self);
531+
532+ self->device = device;
533+ self->iface = g_strdup (iface);
534+ self->channel = channel;
535+ self->channel_watch = channel_watch;
536+ self->stats_update_id = g_timeout_add (rate_ms, update_stats, self);
537+
538+ return self;
539+
540+error:
541+ g_free (self);
542+ return NULL;
543+}
544+
545+void
546+nm_device_statistics_remove (NMDeviceStatistics *self)
547+{
548+ g_source_remove (self->stats_update_id);
549+ g_source_remove (self->channel_watch);
550+ g_io_channel_unref (self->channel);
551+ g_free (self->iface);
552+ g_free (self);
553+}
554diff --git a/src/devices/nm-device-statistics.h b/src/devices/nm-device-statistics.h
555new file mode 100644
556index 0000000..496cecc
557--- /dev/null
558+++ b/src/devices/nm-device-statistics.h
559@@ -0,0 +1,33 @@
560+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
561+/* This program is free software; you can redistribute it and/or modify
562+ * it under the terms of the GNU General Public License as published by
563+ * the Free Software Foundation; either version 2, or (at your option)
564+ * any later version.
565+ *
566+ * This program is distributed in the hope that it will be useful,
567+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
568+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
569+ * GNU General Public License for more details.
570+ *
571+ * You should have received a copy of the GNU General Public License along
572+ * with this program; if not, write to the Free Software Foundation, Inc.,
573+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
574+ *
575+ * Copyright (C) 2016 Canonical Ltd
576+ */
577+
578+#ifndef __NETWORKMANAGER_DEVICE_STATISTICS_H__
579+#define __NETWORKMANAGER_DEVICE_STATISTICS_H__
580+
581+#include <stdlib.h>
582+
583+#include "nm-default.h"
584+
585+typedef struct _NMDeviceStatistics NMDeviceStatistics;
586+
587+NMDeviceStatistics *
588+nm_device_statistics_create (NMDevice *device, const char *iface, unsigned rate_ms);
589+
590+void nm_device_statistics_remove (NMDeviceStatistics *self);
591+
592+#endif /* __NETWORKMANAGER_DEVICE_STATISTICS_H__ */
593diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
594index 8472ff8..eddd0ad 100644
595--- a/src/devices/nm-device.c
596+++ b/src/devices/nm-device.c
597@@ -64,11 +64,13 @@
598 #include "sd-ipv4ll.h"
599 #include "nm-audit-manager.h"
600 #include "nm-arping-manager.h"
601+#include "nm-device-statistics.h"
602
603 #include "nm-device-logging.h"
604 _LOG_DECLARE_SELF (NMDevice);
605
606 #include "nmdbus-device.h"
607+#include "nmdbus-device-statistics.h"
608
609 G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_EXPORTED_OBJECT)
610
611@@ -124,6 +126,9 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDevice,
612 PROP_LLDP_NEIGHBORS,
613 PROP_REAL,
614 PROP_SLAVES,
615+ PROP_REFRESH_RATE_MS,
616+ PROP_TX_BYTES,
617+ PROP_RX_BYTES,
618 );
619
620 #define DEFAULT_AUTOCONNECT TRUE
621@@ -369,6 +374,13 @@ typedef struct _NMDevicePrivate {
622 NMLldpListener *lldp_listener;
623
624 guint check_delete_unrealized_id;
625+
626+ guint32 refresh_rate_ms;
627+ guint64 tx_bytes;
628+ guint64 rx_bytes;
629+
630+ NMDeviceStatistics *statistics;
631+
632 } NMDevicePrivate;
633
634 static gboolean nm_device_set_ip4_config (NMDevice *self,
635@@ -656,6 +668,36 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
636 g_free (old_ip_iface);
637 }
638
639+void
640+nm_device_set_tx_bytes (NMDevice *self, guint64 tx_bytes)
641+{
642+ NMDevicePrivate *priv;
643+
644+ g_return_if_fail (NM_IS_DEVICE (self));
645+
646+ priv = NM_DEVICE_GET_PRIVATE (self);
647+ if (tx_bytes == priv->tx_bytes)
648+ return;
649+
650+ priv->tx_bytes = tx_bytes;
651+ _notify (self, PROP_TX_BYTES);
652+}
653+
654+void
655+nm_device_set_rx_bytes (NMDevice *self, guint64 rx_bytes)
656+{
657+ NMDevicePrivate *priv;
658+
659+ g_return_if_fail (NM_IS_DEVICE (self));
660+
661+ priv = NM_DEVICE_GET_PRIVATE (self);
662+ if (rx_bytes == priv->rx_bytes)
663+ return;
664+
665+ priv->rx_bytes = rx_bytes;
666+ _notify (self, PROP_RX_BYTES);
667+}
668+
669 static gboolean
670 get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid)
671 {
672@@ -11157,6 +11199,11 @@ nm_device_init (NMDevice *self)
673
674 priv->v4_commit_first_time = TRUE;
675 priv->v6_commit_first_time = TRUE;
676+
677+ priv->refresh_rate_ms = 0;
678+ priv->tx_bytes = 0;
679+ priv->rx_bytes = 0;
680+ priv->statistics = NULL;
681 }
682
683 static GObject*
684@@ -11295,6 +11342,11 @@ dispose (GObject *object)
685 g_clear_object (&priv->lldp_listener);
686 }
687
688+ if (priv->statistics) {
689+ nm_device_statistics_remove (priv->statistics);
690+ priv->statistics = NULL;
691+ }
692+
693 G_OBJECT_CLASS (nm_device_parent_class)->dispose (object);
694
695 if (nm_clear_g_source (&priv->queued_state.id)) {
696@@ -11342,7 +11394,7 @@ set_property (GObject *object, guint prop_id,
697 NMDevice *self = NM_DEVICE (object);
698 NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
699 const char *hw_addr, *p;
700- guint count;
701+ guint count, refresh_rate_ms;
702
703 switch (prop_id) {
704 case PROP_UDI:
705@@ -11447,6 +11499,24 @@ set_property (GObject *object, guint prop_id,
706 priv->hw_addr = NULL;
707 }
708 break;
709+ case PROP_REFRESH_RATE_MS:
710+ refresh_rate_ms = g_value_get_uint (value);
711+ if (priv->refresh_rate_ms == refresh_rate_ms)
712+ break;
713+
714+ priv->refresh_rate_ms = g_value_get_uint (value);
715+ _LOGI (LOGD_DEVICE, "statistics refresh rate set to %u ms", priv->refresh_rate_ms);
716+
717+ if (priv->statistics) {
718+ nm_device_statistics_remove (priv->statistics);
719+ priv->statistics = NULL;
720+ }
721+ if (priv->refresh_rate_ms)
722+ priv->statistics =
723+ nm_device_statistics_create (self,
724+ nm_device_get_ip_iface (self),
725+ priv->refresh_rate_ms);
726+ break;
727 default:
728 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
729 break;
730@@ -11605,6 +11675,15 @@ get_property (GObject *object, guint prop_id,
731 g_value_take_boxed (value, slave_list);
732 break;
733 }
734+ case PROP_REFRESH_RATE_MS:
735+ g_value_set_uint (value, priv->refresh_rate_ms);
736+ break;
737+ case PROP_TX_BYTES:
738+ g_value_set_uint64 (value, priv->tx_bytes);
739+ break;
740+ case PROP_RX_BYTES:
741+ g_value_set_uint64 (value, priv->rx_bytes);
742+ break;
743 default:
744 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
745 break;
746@@ -11848,6 +11927,23 @@ nm_device_class_init (NMDeviceClass *klass)
747 G_PARAM_READABLE |
748 G_PARAM_STATIC_STRINGS);
749
750+ /* Statistics */
751+ obj_properties[PROP_REFRESH_RATE_MS] =
752+ g_param_spec_uint (NM_DEVICE_STATISTICS_REFRESH_RATE_MS, "", "",
753+ 0, UINT_MAX, 0,
754+ G_PARAM_READWRITE |
755+ G_PARAM_STATIC_STRINGS);
756+ obj_properties[PROP_TX_BYTES] =
757+ g_param_spec_uint64 (NM_DEVICE_STATISTICS_TX_BYTES, "", "",
758+ 0, UINT64_MAX, 0,
759+ G_PARAM_READABLE |
760+ G_PARAM_STATIC_STRINGS);
761+ obj_properties[PROP_RX_BYTES] =
762+ g_param_spec_uint64 (NM_DEVICE_STATISTICS_RX_BYTES, "", "",
763+ 0, UINT64_MAX, 0,
764+ G_PARAM_READABLE |
765+ G_PARAM_STATIC_STRINGS);
766+
767 g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
768
769 /* Signals */
770@@ -11918,4 +12014,8 @@ nm_device_class_init (NMDeviceClass *klass)
771 "Disconnect", impl_device_disconnect,
772 "Delete", impl_device_delete,
773 NULL);
774+
775+ nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
776+ NMDBUS_TYPE_DEVICE_STATISTICS_SKELETON,
777+ NULL);
778 }
779diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
780index 9f68985..f226d45 100644
781--- a/src/devices/nm-device.h
782+++ b/src/devices/nm-device.h
783@@ -84,6 +84,10 @@
784 #define NM_DEVICE_STATE_CHANGED "state-changed"
785 #define NM_DEVICE_LINK_INITIALIZED "link-initialized"
786
787+#define NM_DEVICE_STATISTICS_REFRESH_RATE_MS "refresh-rate-ms"
788+#define NM_DEVICE_STATISTICS_TX_BYTES "tx-bytes"
789+#define NM_DEVICE_STATISTICS_RX_BYTES "rx-bytes"
790+
791 G_BEGIN_DECLS
792
793 #define NM_TYPE_DEVICE (nm_device_get_type ())
794diff --git a/src/nm-exported-object.c b/src/nm-exported-object.c
795index 10f7d23..2fdb27c 100644
796--- a/src/nm-exported-object.c
797+++ b/src/nm-exported-object.c
798@@ -257,12 +257,16 @@ nm_exported_object_class_add_interface (NMExportedObjectClass *object_class,
799 g_return_if_fail (NM_IS_EXPORTED_OBJECT_CLASS (object_class));
800 g_return_if_fail (g_type_is_a (dbus_skeleton_type, G_TYPE_DBUS_INTERFACE_SKELETON));
801
802- classinfo = g_slice_new (NMExportedObjectClassInfo);
803- classinfo->skeleton_types = NULL;
804- classinfo->methods = g_array_new (FALSE, FALSE, sizeof (NMExportedObjectDBusMethodImpl));
805- classinfo->properties = g_hash_table_new (g_str_hash, g_str_equal);
806- g_type_set_qdata (G_TYPE_FROM_CLASS (object_class),
807- nm_exported_object_class_info_quark (), classinfo);
808+ classinfo = g_type_get_qdata (G_TYPE_FROM_CLASS (object_class),
809+ nm_exported_object_class_info_quark ());
810+ if (!classinfo) {
811+ classinfo = g_slice_new (NMExportedObjectClassInfo);
812+ classinfo->skeleton_types = NULL;
813+ classinfo->methods = g_array_new (FALSE, FALSE, sizeof (NMExportedObjectDBusMethodImpl));
814+ classinfo->properties = g_hash_table_new (g_str_hash, g_str_equal);
815+ g_type_set_qdata (G_TYPE_FROM_CLASS (object_class),
816+ nm_exported_object_class_info_quark (), classinfo);
817+ }
818
819 classinfo->skeleton_types = g_slist_prepend (classinfo->skeleton_types,
820 GSIZE_TO_POINTER (dbus_skeleton_type));
821@@ -342,8 +346,6 @@ nm_exported_object_class_add_interface (NMExportedObjectClass *object_class,
822 }
823 }
824
825- g_assert_cmpint (n_method_signals, ==, classinfo->methods->len);
826-
827 g_type_class_unref (dbus_object_class);
828 }
829
830diff --git a/src/nm-types.h b/src/nm-types.h
831index 997723e..8f859e8 100644
832--- a/src/nm-types.h
833+++ b/src/nm-types.h
834@@ -40,6 +40,7 @@ typedef struct _NMConnectionProvider NMConnectionProvider;
835 typedef struct _NMConnectivity NMConnectivity;
836 typedef struct _NMDefaultRouteManager NMDefaultRouteManager;
837 typedef struct _NMDevice NMDevice;
838+typedef struct _NMDeviceStatistics NMDeviceStatistics;
839 typedef struct _NMDhcp4Config NMDhcp4Config;
840 typedef struct _NMDhcp6Config NMDhcp6Config;
841 typedef struct _NMIP4Config NMIP4Config;
diff --git a/debian/patches/series b/debian/patches/series
index f0a8f73..4bd2565 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -22,3 +22,4 @@ Modify-NMDeviceModem-s-available-logic.patch
22Track-killswitch-change-signals-from-urfkill.patch22Track-killswitch-change-signals-from-urfkill.patch
23Only-test-team-devices-if-we-built-support-for-them.patch23Only-test-team-devices-if-we-built-support-for-them.patch
24Disable-general-with-expect-which-tends-to-fail-on-p.patch24Disable-general-with-expect-which-tends-to-fail-on-p.patch
25Add-statistics-interface.patch

Subscribers

People subscribed via source and target branches