From bb54a548de355baeeac30fb9a7d6680f220810f1 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 4 Jan 2015 16:48:53 +0100 Subject: [PATCH] #250: BSD implementation --- psutil/_psbsd.py | 13 +++ psutil/_psutil_bsd.c | 221 +++++++++++++++++++++++++++++++++++++++++ psutil/_psutil_linux.c | 6 +- 3 files changed, 237 insertions(+), 3 deletions(-) diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 87dfb7a61..c572f011c 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -18,6 +18,7 @@ from . import _psutil_posix as cext_posix from ._common import conn_tmap, usage_percent, sockfam_to_enum from ._common import socktype_to_enum +from ._common import NIC_DUPLEX_FULL, NIC_DUPLEX_HALF, NIC_DUPLEX_UNKNOWN __extra__all__ = [] @@ -207,6 +208,18 @@ def net_connections(kind): return list(ret) +def net_if_stats(): + """Get NIC stats (isup, duplex, speed, mtu).""" + names = net_io_counters().keys() + ret = {} + for name in names: + isup, duplex, speed, mtu = cext.net_if_stats(name) + if hasattr(_common, 'NicDuplex'): + duplex = _common.NicDuplex(duplex) + ret[name] = _common.snicstats(isup, duplex, speed, mtu) + return ret + + pids = cext.pids pid_exists = _psposix.pid_exists disk_usage = _psposix.disk_usage diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c index 615c04bae..eb75ba83e 100644 --- a/psutil/_psutil_bsd.c +++ b/psutil/_psutil_bsd.c @@ -28,6 +28,7 @@ #include // for struct xsocket #include #include +#include // for xinpcb struct #include #include @@ -50,6 +51,7 @@ #include // net io counters #include #include +#include #include // process open files/connections #include @@ -2164,6 +2166,223 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) } +/* + * Determine NIC speed. Taken from: + * http://www.i-scream.org/libstatgrab/ + */ +int psutil_get_nic_speed(int ifm_active) +{ + // Assuming only ETHER devices + switch(IFM_TYPE(ifm_active)) { + case IFM_ETHER: + switch(IFM_SUBTYPE(ifm_active)) { +#if defined(IFM_HPNA_1) && ((!defined(IFM_10G_LR)) || (IFM_10G_LR != IFM_HPNA_1)) + // HomePNA 1.0 (1Mb/s) + case(IFM_HPNA_1): + return 1; +#endif + // 10 Mbit + case(IFM_10_T): // 10BaseT - RJ45 + case(IFM_10_2): // 10Base2 - Thinnet + case(IFM_10_5): // 10Base5 - AUI + case(IFM_10_STP): // 10BaseT over shielded TP + case(IFM_10_FL): // 10baseFL - Fiber + return 10; + // 100 Mbit + case(IFM_100_TX): // 100BaseTX - RJ45 + case(IFM_100_FX): // 100BaseFX - Fiber + case(IFM_100_T4): // 100BaseT4 - 4 pair cat 3 + case(IFM_100_VG): // 100VG-AnyLAN + case(IFM_100_T2): // 100BaseT2 + return 100; + // 1000 Mbit + case(IFM_1000_SX): // 1000BaseSX - multi-mode fiber + case(IFM_1000_LX): // 1000baseLX - single-mode fiber + case(IFM_1000_CX): // 1000baseCX - 150ohm STP +#if defined(IFM_1000_TX) && !defined(OPENBSD) + // FreeBSD 4 and others (but NOT OpenBSD)? + case(IFM_1000_TX): +#endif +#ifdef IFM_1000_FX + case(IFM_1000_FX): +#endif +#ifdef IFM_1000_T + case(IFM_1000_T): +#endif + return 1000; +#if defined(IFM_10G_SR) || defined(IFM_10G_LR) || defined(IFM_10G_CX4) || defined(IFM_10G_T) +# ifdef IFM_10G_SR + case(IFM_10G_SR): +# endif +# ifdef IFM_10G_LR + case(IFM_10G_LR): +# endif +# ifdef IFM_10G_CX4 + case(IFM_10G_CX4): +# endif +# ifdef IFM_10G_TWINAX + case(IFM_10G_TWINAX): +# endif +# ifdef IFM_10G_TWINAX_LONG + case(IFM_10G_TWINAX_LONG): +# endif +# ifdef IFM_10G_T + case(IFM_10G_T): +# endif + return 10000; +#endif +#if defined(IFM_2500_SX) +# ifdef IFM_2500_SX + case(IFM_2500_SX): +# endif + return 2500; +#endif // any 2.5GBit stuff... + // We don't know what it is + default: + return 0; + } + break; + +#ifdef IFM_TOKEN + case IFM_TOKEN: + switch(IFM_SUBTYPE(ifm_active)) { + case IFM_TOK_STP4: // Shielded twisted pair 4m - DB9 + case IFM_TOK_UTP4: // Unshielded twisted pair 4m - RJ45 + return 4; + case IFM_TOK_STP16: // Shielded twisted pair 16m - DB9 + case IFM_TOK_UTP16: // Unshielded twisted pair 16m - RJ45 + return 16; +#if defined(IFM_TOK_STP100) || defined(IFM_TOK_UTP100) +# ifdef IFM_TOK_STP100 + case IFM_TOK_STP100: // Shielded twisted pair 100m - DB9 +# endif +# ifdef IFM_TOK_UTP100 + case IFM_TOK_UTP100: // Unshielded twisted pair 100m - RJ45 +# endif + return 100; +#endif + // We don't know what it is + default: + return 0; + } + break; +#endif + +#ifdef IFM_FDDI + case IFM_FDDI: + switch(IFM_SUBTYPE(ifm_active)) { + // We don't know what it is + default: + return 0; + } + break; +#endif + case IFM_IEEE80211: + switch(IFM_SUBTYPE(ifm_active)) { + case IFM_IEEE80211_FH1: // Frequency Hopping 1Mbps + case IFM_IEEE80211_DS1: // Direct Sequence 1Mbps + return 1; + case IFM_IEEE80211_FH2: // Frequency Hopping 2Mbps + case IFM_IEEE80211_DS2: // Direct Sequence 2Mbps + return 2; + case IFM_IEEE80211_DS5: // Direct Sequence 5Mbps + return 5; + case IFM_IEEE80211_DS11: // Direct Sequence 11Mbps + return 11; + case IFM_IEEE80211_DS22: // Direct Sequence 22Mbps + return 22; + // We don't know what it is + default: + return 0; + } + break; + + default: + return 0; + } +} + + +/* + * Return stats about a particular network interface. + * References: + * http://www.i-scream.org/libstatgrab/ + */ +static PyObject * +psutil_net_if_stats(PyObject *self, PyObject *args) +{ + char *nic_name; + int sock = 0; + int ret; + int duplex; + int speed; + struct ifreq ifr; + struct ifmediareq ifmed; + + PyObject *py_is_up = NULL; + PyObject *py_mtu = NULL; + + if (! PyArg_ParseTuple(args, "s", &nic_name)) + return NULL; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + goto error; + strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); + + // is up? + ret = ioctl(sock, SIOCGIFFLAGS, &ifr); + if (ret == -1) + goto error; + if ((ifr.ifr_flags & IFF_UP) != 0) + py_is_up = Py_True; + else + py_is_up = Py_False; + Py_INCREF(py_is_up); + + // MTU + ret = ioctl(sock, SIOCGIFMTU, &ifr); + if (ret == -1) + goto error; + py_mtu = Py_BuildValue("i", ifr.ifr_mtu); + if (!py_mtu) + goto error; + Py_INCREF(py_mtu); + + // speed / duplex + memset(&ifmed, 0, sizeof(struct ifmediareq)); + strlcpy(ifmed.ifm_name, nic_name, sizeof(ifmed.ifm_name)); + ret = ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed); + if (ret == -1) { + speed = 0; + duplex = 0; + } + else { + speed = psutil_get_nic_speed(ifmed.ifm_active); + if ((ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active) + duplex = 2; + else if ((ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active) + duplex = 1; + else + duplex = 0; + } + + close(sock); + Py_DECREF(py_is_up); + Py_DECREF(py_mtu); + + return Py_BuildValue("[OiiO]", py_is_up, duplex, speed, py_mtu); + +error: + Py_XDECREF(py_is_up); + Py_XDECREF(py_mtu); + if (sock != 0) + close(sock); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + /* * define the psutil C module methods and initialize the module. */ @@ -2251,6 +2470,8 @@ PsutilMethods[] = "Return currently connected users as a list of tuples"}, {"net_connections", psutil_net_connections, METH_VARARGS, "Return system-wide open connections."}, + {"net_if_stats", psutil_net_if_stats, METH_VARARGS, + "Return NIC stats."}, {NULL, NULL, 0, NULL} }; diff --git a/psutil/_psutil_linux.c b/psutil/_psutil_linux.c index 8ea0e303d..cd1eb002e 100644 --- a/psutil/_psutil_linux.c +++ b/psutil/_psutil_linux.c @@ -481,8 +481,8 @@ psutil_users(PyObject *self, PyObject *args) /* - * Return stats (isup?, duplex, speed) about a particular network - * interface. References: + * Return stats about a particular network interface. + * References: * https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py * http://www.i-scream.org/libstatgrab/ */ @@ -506,7 +506,7 @@ psutil_net_if_stats(PyObject* self, PyObject* args) sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) goto error; - strncpy(ifr.ifr_name, nic_name, sizeof ifr.ifr_name); + strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); // is up? ret = ioctl(sock, SIOCGIFFLAGS, &ifr);