Skip to content

Commit

Permalink
#250: BSD implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
giampaolo committed Jan 4, 2015
1 parent 5e0e458 commit bb54a54
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 3 deletions.
13 changes: 13 additions & 0 deletions psutil/_psbsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__ = []
Expand Down Expand Up @@ -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
Expand Down
221 changes: 221 additions & 0 deletions psutil/_psutil_bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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>
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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}
};
Expand Down
6 changes: 3 additions & 3 deletions psutil/_psutil_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -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/
*/
Expand All @@ -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);
Expand Down

0 comments on commit bb54a54

Please sign in to comment.