Skip to content

Commit

Permalink
#540 detect interface speed on linux using ethtool ioctl, expose it t…
Browse files Browse the repository at this point in the history
…o the server as "connection-data.speed"

git-svn-id: https://xpra.org/svn/Xpra/trunk@16825 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Sep 11, 2017
1 parent adff48f commit b9268bb
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 5 deletions.
9 changes: 8 additions & 1 deletion src/setup.py
Expand Up @@ -168,6 +168,7 @@ def is_RH():
minify_ENABLED = html5_ENABLED
pam_ENABLED = DEFAULT and (server_ENABLED or proxy_ENABLED) and POSIX and not OSX and (os.path.exists("/usr/include/pam/pam_misc.h") or os.path.exists("/usr/include/security/pam_misc.h"))

netdev_ENABLED = LINUX and DEFAULT
vsock_ENABLED = LINUX and os.path.exists("/usr/include/linux/vm_sockets.h")
bencode_ENABLED = DEFAULT
cython_bencode_ENABLED = DEFAULT
Expand Down Expand Up @@ -218,7 +219,7 @@ def is_RH():
"v4l2",
"dec_avcodec2", "csc_swscale",
"csc_libyuv",
"bencode", "cython_bencode", "vsock", "mdns",
"bencode", "cython_bencode", "vsock", "netdev", "mdns",
"clipboard",
"server", "client", "dbus", "x11", "xinput", "uinput", "sd_listen",
"gtk_x11", "service",
Expand Down Expand Up @@ -2125,6 +2126,12 @@ def which(cmd):
["xpra/net/bencode/cython_bencode.pyx"],
**bencode_pkgconfig))

if netdev_ENABLED:
netdev_pkgconfig = pkgconfig()
cython_add(Extension("xpra.platform.xposix.netdev_query",
["xpra/platform/xposix/netdev_query.pyx"],
**netdev_pkgconfig))

if vsock_ENABLED:
vsock_pkgconfig = pkgconfig()
cython_add(Extension("xpra.net.vsock",
Expand Down
6 changes: 6 additions & 0 deletions src/xpra/client/client_base.py
Expand Up @@ -380,6 +380,12 @@ def up(prefix, d):
mid = get_machine_id()
if mid:
capabilities["machine_id"] = mid
#get socket speed if we have it:
pinfo = self._protocol.get_info()
netlog("protocol info=%s", pinfo)
socket_speed = pinfo.get("socket", {}).get("speed")
if socket_speed:
capabilities["connection-data"] = {"speed" : socket_speed}

if self.encryption:
assert self.encryption in ENCRYPTION_CIPHERS
Expand Down
13 changes: 12 additions & 1 deletion src/xpra/net/bytestreams.py
Expand Up @@ -320,7 +320,18 @@ def do_get_socket_info(self):
except:
pass
try:
info["fileno"] = s.fileno()
fd = s.fileno()
info["fileno"] = fd
from xpra.platform.netdev_query import get_interface_speed
#ie: self.local = ("192.168.1.7", "14500")
if self.local and len(self.local)==2:
from xpra.net.net_util import get_interface
iface = get_interface(self.local[0])
#ie: iface = "eth0"
if iface and iface!="lo":
s = get_interface_speed(fd, iface)
if s>0:
info["speed"] = s
except:
pass
return info
Expand Down
26 changes: 23 additions & 3 deletions src/xpra/net/net_util.py
Expand Up @@ -21,7 +21,7 @@
netifaces_version = netifaces.version #@UndefinedVariable
except:
has_netifaces = False
log.warn("python netifaces package is missing")
log.warn("Warning: the python netifaces package is missing")
iface_ipmasks = {}
bind_IPs = None

Expand All @@ -36,8 +36,28 @@ def get_free_tcp_port():

def get_interfaces():
if not has_netifaces:
return []
return netifaces.interfaces() #@UndefinedVariable
return []
return netifaces.interfaces() #@UndefinedVariable

def get_interfaces_addresses():
d = {}
for iface in get_interfaces():
d[iface] = netifaces.ifaddresses(iface) #@UndefinedVariable
return d

def get_interface(address):
for iface, idefs in get_interfaces_addresses().items():
#ie: {
# 17: [{'broadcast': u'ff:ff:ff:ff:ff:ff', 'addr': u'00:e0:4c:68:46:a6'}],
# 2: [{'broadcast': u'192.168.1.255', 'netmask': u'255.255.255.0', 'addr': u'192.168.1.7'}],
# 10: [{'netmask': u'ffff:ffff:ffff:ffff::/64', 'addr': u'fe80::6c45:655:c59e:92a1%eth0'}]
#}
for _itype, defs in idefs.items():
#ie: itype=2, defs=[{'broadcast': u'192.168.1.255', 'netmask': u'255.255.255.0', 'addr': u'192.168.1.7'}]
for props in defs:
if props.get("addr")==address:
return iface
return None

def get_gateways():
if not has_netifaces:
Expand Down
12 changes: 12 additions & 0 deletions src/xpra/platform/netdev_query.py
@@ -0,0 +1,12 @@
# This file is part of Xpra.
# Copyright (C) 2017 Antoine Martin <antoine@devloop.org.uk>
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
# later version. See the file COPYING for details.

def get_interface_speed(*_args):
return 0

from xpra.platform import platform_import
platform_import(globals(), "netdev_query", False,
"get_interface_speed",
)
72 changes: 72 additions & 0 deletions src/xpra/platform/xposix/netdev_query.pyx
@@ -0,0 +1,72 @@
# This file is part of Xpra.
# Copyright (C) 2017 Antoine Martin <antoine@devloop.org.uk>
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
# later version. See the file COPYING for details.

from __future__ import absolute_import

import os

from libc.stdint cimport uintptr_t, uint32_t, uint16_t, uint8_t

from xpra.log import Logger
log = Logger("util", "network")

ctypedef uint32_t __u32
ctypedef uint16_t __u16
ctypedef uint8_t __u8
cdef extern from "linux/ethtool.h":
int ETHTOOL_GSET
cdef struct ethtool_cmd:
__u32 cmd
__u32 supported
__u32 advertising
__u16 speed
__u8 duplex
__u8 port
__u8 phy_address
__u8 transceiver
__u8 autoneg
__u8 mdio_support
__u32 maxtxpkt
__u32 maxrxpkt
__u16 speed_hi
__u8 eth_tp_mdix
__u8 eth_tp_mdix_ctrl
__u32 lp_advertising
__u32 reserved[2]


cdef extern from "linux/sockios.h":
int SIOCETHTOOL

cdef extern from "net/if.h":
DEF IFNAMSIZ=16
cdef struct ifr_ifrn:
char ifrn_name[IFNAMSIZ]
cdef struct ifr_ifru:
int ifru_flags
int ifru_ivalue
int ifru_mtu
void *ifru_data
cdef struct ifreq:
ifr_ifrn ifr_ifrn
ifr_ifru ifr_ifru

cdef extern from "sys/ioctl.h":
int ioctl(int fd, unsigned long request, ...)


def get_interface_speed(int sockfd, char *ifname):
""" returns the ethtool speed in Mbps, or 0 """
cdef ifreq ifr
cdef ethtool_cmd edata
ifr.ifr_ifrn.ifrn_name = ifname
ifr.ifr_ifru.ifru_data = <void*> &edata
edata.cmd = ETHTOOL_GSET
cdef int r = ioctl(sockfd, SIOCETHTOOL, &ifr)
if r < 0:
log.warn("Warning: failed to query %s device properties with SIOCETHTOOL", ifname)
log.warn(" error %i", r)
return 0
return edata.speed*1000*1000

0 comments on commit b9268bb

Please sign in to comment.