summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2015-02-12 16:59:25 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2015-02-12 16:59:25 +0100
commitf8bad8c54f83028edef8faffe21d9d9ae308ad98 (patch)
treed6eee31206520fd6f3fee61510a374e5a3bd395e
parent769f07703e61b5ebe2f1bdb586861b490f4ae3fb (diff)
downloadpsutil-f8bad8c54f83028edef8faffe21d9d9ae308ad98.tar.gz
#250: Solaris implementation
-rw-r--r--psutil/_pssunos.py11
-rw-r--r--psutil/_psutil_sunos.c112
-rw-r--r--setup.py2
-rw-r--r--test/_sunos.py6
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}
};
diff --git a/setup.py b/setup.py
index 89e9353e..54a70c49 100644
--- a/setup.py
+++ b/setup.py
@@ -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()