summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2015-01-04 16:48:53 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2015-01-04 16:48:53 +0100
commitbb54a548de355baeeac30fb9a7d6680f220810f1 (patch)
treef1e757efad1a574a94d63759c78b8cc1ccfeef9e
parent5e0e458aa09f6dc84b89cdd801671536d89e8306 (diff)
downloadpsutil-bb54a548de355baeeac30fb9a7d6680f220810f1.tar.gz
#250: BSD implementation
-rw-r--r--psutil/_psbsd.py13
-rw-r--r--psutil/_psutil_bsd.c221
-rw-r--r--psutil/_psutil_linux.c6
3 files changed, 237 insertions, 3 deletions
diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py
index 87dfb7a6..c572f011 100644
--- a/psutil/_psbsd.py
+++ b/psutil/_psbsd.py
@@ -18,6 +18,7 @@ from . import _psutil_bsd as cext
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 615c04ba..eb75ba83 100644
--- a/psutil/_psutil_bsd.c
+++ b/psutil/_psutil_bsd.c
@@ -28,6 +28,7 @@
#include <sys/socketvar.h> // for struct xsocket
#include <sys/un.h>
#include <sys/unpcb.h>
+#include <sys/sockio.h>
// for xinpcb struct
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -50,6 +51,7 @@
#include <net/if.h> // net io counters
#include <net/if_dl.h>
#include <net/route.h>
+#include <net/if_media.h>
#include <netinet/in.h> // process open files/connections
#include <sys/un.h>
@@ -2165,6 +2167,223 @@ error:
/*
+ * 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.
*/
static PyMethodDef
@@ -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 8ea0e303..cd1eb002 100644
--- a/psutil/_psutil_linux.c
+++ b/psutil/_psutil_linux.c
@@ -481,8 +481,8 @@ error:
/*
- * 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);