diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2015-02-12 16:59:25 +0100 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2015-02-12 16:59:25 +0100 |
commit | f8bad8c54f83028edef8faffe21d9d9ae308ad98 (patch) | |
tree | d6eee31206520fd6f3fee61510a374e5a3bd395e | |
parent | 769f07703e61b5ebe2f1bdb586861b490f4ae3fb (diff) | |
download | psutil-f8bad8c54f83028edef8faffe21d9d9ae308ad98.tar.gz |
#250: Solaris implementation
-rw-r--r-- | psutil/_pssunos.py | 11 | ||||
-rw-r--r-- | psutil/_psutil_sunos.c | 112 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | test/_sunos.py | 6 |
4 files changed, 130 insertions, 1 deletions
diff --git a/psutil/_pssunos.py b/psutil/_pssunos.py index de15b56d..b02526dd 100644 --- a/psutil/_pssunos.py +++ b/psutil/_pssunos.py @@ -231,6 +231,17 @@ def net_connections(kind, _pid=-1): return list(ret) +def net_if_stats(): + """Get NIC stats (isup, duplex, speed, mtu).""" + ret = cext.net_if_stats() + for name, items in ret.items(): + isup, duplex, speed, mtu = items + if hasattr(_common, 'NicDuplex'): + duplex = _common.NicDuplex(duplex) + ret[name] = _common.snicstats(isup, duplex, speed, mtu) + return ret + + def wrap_exceptions(fun): """Call callable into a try/except clause and translate ENOENT, EACCES and EPERM in NoSuchProcess or AccessDenied exceptions. diff --git a/psutil/_psutil_sunos.c b/psutil/_psutil_sunos.c index 32108e09..87d5cfd3 100644 --- a/psutil/_psutil_sunos.c +++ b/psutil/_psutil_sunos.c @@ -30,6 +30,8 @@ #include <sys/mntent.h> // for MNTTAB #include <sys/mnttab.h> #include <sys/procfs.h> +#include <sys/sockio.h> +#include <sys/socket.h> #include <fcntl.h> #include <utmpx.h> #include <kstat.h> @@ -38,6 +40,7 @@ #include <stropts.h> #include <inet/tcp.h> #include <arpa/inet.h> +#include <net/if.h> #include "_psutil_sunos.h" @@ -1152,6 +1155,113 @@ error: /* + * 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/ + */ +static PyObject* +psutil_net_if_stats(PyObject* self, PyObject* args) +{ + kstat_ctl_t *kc = NULL; + kstat_t *ksp; + kstat_named_t *knp; + int ret; + int sock = 0; + int speed; + int duplex; + int mtu; + + PyObject *py_retdict = PyDict_New(); + PyObject *py_ifc_info = NULL; + PyObject *py_is_up = NULL; + PyObject *py_ret = NULL; + + if (py_retdict == NULL) + return NULL; + kc = kstat_open(); + if (kc == NULL) + return PyErr_SetFromErrno(PyExc_OSError); + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + return PyErr_SetFromErrno(PyExc_OSError); + + for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { + if (strcmp(ksp->ks_class, "net") == 0) { + struct ifreq ifr; + + kstat_read(kc, ksp, NULL); + if (ksp->ks_type != KSTAT_TYPE_NAMED) + continue; + if (strcmp(ksp->ks_class, "net") != 0) + continue; + + strncpy(ifr.ifr_name, ksp->ks_name, sizeof(ifr.ifr_name)); + ret = ioctl(sock, SIOCGIFFLAGS, &ifr); + if (ret == -1) + continue; // not a network interface + + // is up? + if ((ifr.ifr_flags & IFF_UP) != 0) { + if ((knp = kstat_data_lookup(ksp, "link_up")) != NULL) { + if (knp->value.ui32 != 0u) + py_is_up = Py_True; + else + py_is_up = Py_False; + } + else { + py_is_up = Py_True; + } + } + else { + py_is_up = Py_False; + } + Py_INCREF(py_is_up); + + // duplex + duplex = 0; // unknown + if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) { + if (knp->value.ui32 == 1) + duplex = 1; // half + else if (knp->value.ui32 == 2) + duplex = 2; // full + } + + // speed + if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL) + speed = knp->value.ui64 / 10000000; + else + speed = 0; + + // mtu + ret = ioctl(sock, SIOCGIFMTU, &ifr); + if (ret == -1) + goto error; + mtu = ifr.ifr_mtu; + + py_ifc_info = Py_BuildValue("(Oiii)", py_is_up, duplex, speed, mtu); + if (!py_ifc_info) + goto error; + if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_ifc_info)) + goto error; + Py_DECREF(py_ifc_info); + } + } + + close(sock); + return py_retdict; + +error: + Py_XDECREF(py_is_up); + if (sock != 0) + close(sock); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +/* * define the psutil C module methods and initialize the module. */ static PyMethodDef @@ -1192,6 +1302,8 @@ PsutilMethods[] = "Return the number of physical CPUs on the system."}, {"net_connections", psutil_net_connections, METH_VARARGS, "Return TCP and UDP syste-wide open connections."}, + {"net_if_stats", psutil_net_if_stats, METH_VARARGS, + "Return NIC stats (isup, duplex, speed, mtu)"}, {NULL, NULL, 0, NULL} }; @@ -131,7 +131,7 @@ elif sys.platform.lower().startswith('sunos'): 'psutil._psutil_sunos', sources=['psutil/_psutil_sunos.c'], define_macros=[VERSION_MACRO], - libraries=['kstat', 'nsl'],), + libraries=['kstat', 'nsl', 'socket']), posix_extension, ] else: diff --git a/test/_sunos.py b/test/_sunos.py index 7fdc50b6..be2d10b1 100644 --- a/test/_sunos.py +++ b/test/_sunos.py @@ -34,6 +34,12 @@ class SunOSSpecificTestCase(unittest.TestCase): self.assertEqual(psutil_swap.used, used) self.assertEqual(psutil_swap.free, free) + def test_nic_names(self): + # Internally the C implementation uses almost the same + # routine so we want to make sure NIC names are the same. + self.assertEqual(sorted(psutil.net_io_counters(pernic=True).keys()), + sorted(psutil.net_if_stats().keys())) + def test_main(): test_suite = unittest.TestSuite() |