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