diff options
author | Chris Lalancette <clalancette@gmail.com> | 2022-09-06 12:23:08 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-06 18:23:08 +0200 |
commit | 70eecaf44d61f2cabcd22ffb407b904242a122c9 (patch) | |
tree | 29d605b10d7cde532d5aade3b9939bc16c94988b | |
parent | 9f9a82d02c901f62512236b44edb050f84cbe5b6 (diff) | |
download | psutil-70eecaf44d61f2cabcd22ffb407b904242a122c9.tar.gz |
Add in support for network interface flags. (#2037)
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
-rw-r--r-- | CREDITS | 4 | ||||
-rw-r--r-- | HISTORY.rst | 1 | ||||
-rw-r--r-- | README.rst | 4 | ||||
-rw-r--r-- | docs/index.rst | 14 | ||||
-rw-r--r-- | psutil/_common.py | 3 | ||||
-rw-r--r-- | psutil/_psaix.py | 7 | ||||
-rw-r--r-- | psutil/_psbsd.py | 7 | ||||
-rw-r--r-- | psutil/_pslinux.py | 7 | ||||
-rw-r--r-- | psutil/_psosx.py | 7 | ||||
-rw-r--r-- | psutil/_pssunos.py | 2 | ||||
-rw-r--r-- | psutil/_psutil_posix.c | 201 | ||||
-rw-r--r-- | psutil/_pswindows.py | 2 | ||||
-rwxr-xr-x | psutil/tests/test_system.py | 3 |
13 files changed, 246 insertions, 16 deletions
@@ -789,3 +789,7 @@ I: 2099 N: Torsten Blum I: 2114 + +N: Chris Lalancette +W: https://github.com/clalancette +I: 2037 diff --git a/HISTORY.rst b/HISTORY.rst index 7767c08a..572c7f26 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -24,6 +24,7 @@ - 1053_: drop Python 2.6 support. (patches by Matthieu Darbois and Hugo van Kemenade) +- 2037_: Add additional flags to net_if_stats. - 2050_, [Linux]: increase ``read(2)`` buffer size from 1k to 32k when reading ``/proc`` pseudo files line by line. This should help having more consistent results. @@ -252,8 +252,8 @@ Network snicaddr(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]} >>> >>> psutil.net_if_stats() - {'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536), - 'wlan0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500)} + {'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536, flags='up,loopback,running'), + 'wlan0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500, flags='up,broadcast,running,multicast')} >>> Sensors diff --git a/docs/index.rst b/docs/index.rst index 8d663c7e..c30f7d6a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -735,13 +735,21 @@ Network - **speed**: the NIC speed expressed in mega bits (MB), if it can't be determined (e.g. 'localhost') it will be set to ``0``. - **mtu**: NIC's maximum transmission unit expressed in bytes. + - **flags**: a string of comma-separated flags on the interface (may be an empty string). + Possible flags are: ``up``, ``broadcast``, ``debug``, ``loopback``, + ``pointopoint``, ``notrailers``, ``running``, ``noarp``, ``promisc``, + ``allmulti``, ``master``, ``slave``, ``multicast``, ``portsel``, + ``dynamic``, ``oactive``, ``simplex``, ``link0``, ``link1``, ``link2``, + and ``d2`` (some flags are only available on certain platforms). + + Availability: UNIX Example: >>> import psutil >>> psutil.net_if_stats() - {'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500), - 'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)} + {'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500, flags='up,broadcast,running,multicast'), + 'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536, flags='up,loopback,running')} Also see `nettop.py`_ and `ifconfig.py`_ for an example application. @@ -749,6 +757,8 @@ Network .. versionchanged:: 5.7.3 `isup` on UNIX also checks whether the NIC is running. + .. versionchanged:: 5.9.3 *flags* field was added on POSIX. + Sensors ------- diff --git a/psutil/_common.py b/psutil/_common.py index 9937eb83..3414e8ca 100644 --- a/psutil/_common.py +++ b/psutil/_common.py @@ -199,7 +199,8 @@ sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr', snicaddr = namedtuple('snicaddr', ['family', 'address', 'netmask', 'broadcast', 'ptp']) # psutil.net_if_stats() -snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu']) +snicstats = namedtuple('snicstats', + ['isup', 'duplex', 'speed', 'mtu', 'flags']) # psutil.cpu_stats() scpustats = namedtuple( 'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls']) diff --git a/psutil/_psaix.py b/psutil/_psaix.py index 9cc7d56e..2391478c 100644 --- a/psutil/_psaix.py +++ b/psutil/_psaix.py @@ -237,7 +237,8 @@ def net_if_stats(): names = set([x[0] for x in net_if_addrs()]) ret = {} for name in names: - isup, mtu = cext.net_if_stats(name) + mtu = cext_posix.net_if_mtu(name) + flags = cext_posix.net_if_flags(name) # try to get speed and duplex # TODO: rewrite this in C (entstat forks, so use truss -f to follow. @@ -257,8 +258,10 @@ def net_if_stats(): speed = int(re_result.group(1)) duplex = re_result.group(2) + output_flags = ','.join(flags) + isup = 'running' in flags duplex = duplex_map.get(duplex, NIC_DUPLEX_UNKNOWN) - ret[name] = _common.snicstats(isup, duplex, speed, mtu) + ret[name] = _common.snicstats(isup, duplex, speed, mtu, output_flags) return ret diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 8672ca6e..a25c96cd 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -383,7 +383,7 @@ def net_if_stats(): for name in names: try: mtu = cext_posix.net_if_mtu(name) - isup = cext_posix.net_if_is_running(name) + flags = cext_posix.net_if_flags(name) duplex, speed = cext_posix.net_if_duplex_speed(name) except OSError as err: # https://github.com/giampaolo/psutil/issues/1279 @@ -392,7 +392,10 @@ def net_if_stats(): else: if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) - ret[name] = _common.snicstats(isup, duplex, speed, mtu) + output_flags = ','.join(flags) + isup = 'running' in flags + ret[name] = _common.snicstats(isup, duplex, speed, mtu, + output_flags) return ret diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index e7cef439..57349889 100644 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -1060,7 +1060,7 @@ def net_if_stats(): for name in names: try: mtu = cext_posix.net_if_mtu(name) - isup = cext_posix.net_if_is_running(name) + flags = cext_posix.net_if_flags(name) duplex, speed = cext.net_if_duplex_speed(name) except OSError as err: # https://github.com/giampaolo/psutil/issues/1279 @@ -1069,7 +1069,10 @@ def net_if_stats(): else: debug(err) else: - ret[name] = _common.snicstats(isup, duplex_map[duplex], speed, mtu) + output_flags = ','.join(flags) + isup = 'running' in flags + ret[name] = _common.snicstats(isup, duplex_map[duplex], speed, mtu, + output_flags) return ret diff --git a/psutil/_psosx.py b/psutil/_psosx.py index ac8ecc53..58359bc9 100644 --- a/psutil/_psosx.py +++ b/psutil/_psosx.py @@ -263,7 +263,7 @@ def net_if_stats(): for name in names: try: mtu = cext_posix.net_if_mtu(name) - isup = cext_posix.net_if_is_running(name) + flags = cext_posix.net_if_flags(name) duplex, speed = cext_posix.net_if_duplex_speed(name) except OSError as err: # https://github.com/giampaolo/psutil/issues/1279 @@ -272,7 +272,10 @@ def net_if_stats(): else: if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) - ret[name] = _common.snicstats(isup, duplex, speed, mtu) + output_flags = ','.join(flags) + isup = 'running' in flags + ret[name] = _common.snicstats(isup, duplex, speed, mtu, + output_flags) return ret diff --git a/psutil/_pssunos.py b/psutil/_pssunos.py index 69b579c5..541c1aa4 100644 --- a/psutil/_pssunos.py +++ b/psutil/_pssunos.py @@ -293,7 +293,7 @@ def net_if_stats(): isup, duplex, speed, mtu = items if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) - ret[name] = _common.snicstats(isup, duplex, speed, mtu) + ret[name] = _common.snicstats(isup, duplex, speed, mtu, '') return ret diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c index 04536614..7742eb41 100644 --- a/psutil/_psutil_posix.c +++ b/psutil/_psutil_posix.c @@ -429,6 +429,206 @@ error: return PyErr_SetFromErrno(PyExc_OSError); } +static int +append_flag(PyObject *py_retlist, const char * flag_name) +{ + PyObject *py_str = NULL; + + py_str = PyUnicode_DecodeFSDefault(flag_name); + if (! py_str) + return 0; + if (PyList_Append(py_retlist, py_str)) { + Py_DECREF(py_str); + return 0; + } + Py_CLEAR(py_str); + + return 1; +} + +/* + * Get all of the NIC flags and return them. + */ +static PyObject * +psutil_net_if_flags(PyObject *self, PyObject *args) { + char *nic_name; + int sock = -1; + int ret; + struct ifreq ifr; + PyObject *py_retlist = PyList_New(0); + short int flags; + + if (py_retlist == NULL) + return NULL; + + if (! PyArg_ParseTuple(args, "s", &nic_name)) + goto error; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + PyErr_SetFromOSErrnoWithSyscall("socket(SOCK_DGRAM)"); + goto error; + } + + PSUTIL_STRNCPY(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); + ret = ioctl(sock, SIOCGIFFLAGS, &ifr); + if (ret == -1) { + PyErr_SetFromOSErrnoWithSyscall("ioctl(SIOCGIFFLAGS)"); + goto error; + } + + close(sock); + sock = -1; + + flags = ifr.ifr_flags & 0xFFFF; + + // Linux/glibc IFF flags: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/gnu/net/if.h;h=251418f82331c0426e58707fe4473d454893b132;hb=HEAD + // macOS IFF flags: https://opensource.apple.com/source/xnu/xnu-792/bsd/net/if.h.auto.html + // AIX IFF flags: https://www.ibm.com/support/pages/how-hexadecimal-flags-displayed-ifconfig-are-calculated + // FreeBSD IFF flags: https://www.freebsd.org/cgi/man.cgi?query=if_allmulti&apropos=0&sektion=0&manpath=FreeBSD+10-current&format=html + +#ifdef IFF_UP + // Available in (at least) Linux, macOS, AIX, BSD + if (flags & IFF_UP) + if (!append_flag(py_retlist, "up")) + goto error; +#endif +#ifdef IFF_BROADCAST + // Available in (at least) Linux, macOS, AIX, BSD + if (flags & IFF_BROADCAST) + if (!append_flag(py_retlist, "broadcast")) + goto error; +#endif +#ifdef IFF_DEBUG + // Available in (at least) Linux, macOS, BSD + if (flags & IFF_DEBUG) + if (!append_flag(py_retlist, "debug")) + goto error; +#endif +#ifdef IFF_LOOPBACK + // Available in (at least) Linux, macOS, BSD + if (flags & IFF_LOOPBACK) + if (!append_flag(py_retlist, "loopback")) + goto error; +#endif +#ifdef IFF_POINTOPOINT + // Available in (at least) Linux, macOS, BSD + if (flags & IFF_POINTOPOINT) + if (!append_flag(py_retlist, "pointopoint")) + goto error; +#endif +#ifdef IFF_NOTRAILERS + // Available in (at least) Linux, macOS, AIX + if (flags & IFF_NOTRAILERS) + if (!append_flag(py_retlist, "notrailers")) + goto error; +#endif +#ifdef IFF_RUNNING + // Available in (at least) Linux, macOS, AIX, BSD + if (flags & IFF_RUNNING) + if (!append_flag(py_retlist, "running")) + goto error; +#endif +#ifdef IFF_NOARP + // Available in (at least) Linux, macOS, BSD + if (flags & IFF_NOARP) + if (!append_flag(py_retlist, "noarp")) + goto error; +#endif +#ifdef IFF_PROMISC + // Available in (at least) Linux, macOS, BSD + if (flags & IFF_PROMISC) + if (!append_flag(py_retlist, "promisc")) + goto error; +#endif +#ifdef IFF_ALLMULTI + // Available in (at least) Linux, macOS, BSD + if (flags & IFF_ALLMULTI) + if (!append_flag(py_retlist, "allmulti")) + goto error; +#endif +#ifdef IFF_MASTER + // Available in (at least) Linux + if (flags & IFF_MASTER) + if (!append_flag(py_retlist, "master")) + goto error; +#endif +#ifdef IFF_SLAVE + // Available in (at least) Linux + if (flags & IFF_SLAVE) + if (!append_flag(py_retlist, "slave")) + goto error; +#endif +#ifdef IFF_MULTICAST + // Available in (at least) Linux, macOS, BSD + if (flags & IFF_MULTICAST) + if (!append_flag(py_retlist, "multicast")) + goto error; +#endif +#ifdef IFF_PORTSEL + // Available in (at least) Linux + if (flags & IFF_PORTSEL) + if (!append_flag(py_retlist, "portsel")) + goto error; +#endif +#ifdef IFF_AUTOMEDIA + // Available in (at least) Linux + if (flags & IFF_AUTOMEDIA) + if (!append_flag(py_retlist, "automedia")) + goto error; +#endif +#ifdef IFF_DYNAMIC + // Available in (at least) Linux + if (flags & IFF_DYNAMIC) + if (!append_flag(py_retlist, "dynamic")) + goto error; +#endif +#ifdef IFF_OACTIVE + // Available in (at least) macOS, BSD + if (flags & IFF_OACTIVE) + if (!append_flag(py_retlist, "oactive")) + goto error; +#endif +#ifdef IFF_SIMPLEX + // Available in (at least) macOS, AIX, BSD + if (flags & IFF_SIMPLEX) + if (!append_flag(py_retlist, "simplex")) + goto error; +#endif +#ifdef IFF_LINK0 + // Available in (at least) macOS, BSD + if (flags & IFF_LINK0) + if (!append_flag(py_retlist, "link0")) + goto error; +#endif +#ifdef IFF_LINK1 + // Available in (at least) macOS, BSD + if (flags & IFF_LINK1) + if (!append_flag(py_retlist, "link1")) + goto error; +#endif +#ifdef IFF_LINK2 + // Available in (at least) macOS, BSD + if (flags & IFF_LINK2) + if (!append_flag(py_retlist, "link2")) + goto error; +#endif +#ifdef IFF_D2 + // Available in (at least) AIX + if (flags & IFF_D2) + if (!append_flag(py_retlist, "d2")) + goto error; +#endif + + return py_retlist; + +error: + Py_DECREF(py_retlist); + if (sock != -1) + close(sock); + return NULL; +} + /* * Inspect NIC flags, returns a bool indicating whether the NIC is @@ -667,6 +867,7 @@ static PyMethodDef mod_methods[] = { {"getpagesize", psutil_getpagesize_pywrapper, METH_VARARGS}, {"getpriority", psutil_posix_getpriority, METH_VARARGS}, {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS}, + {"net_if_flags", psutil_net_if_flags, METH_VARARGS}, {"net_if_is_running", psutil_net_if_is_running, METH_VARARGS}, {"net_if_mtu", psutil_net_if_mtu, METH_VARARGS}, {"setpriority", psutil_posix_setpriority, METH_VARARGS}, diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 31edffc1..7d882b77 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -386,7 +386,7 @@ def net_if_stats(): isup, duplex, speed, mtu = items if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) - ret[name] = _common.snicstats(isup, duplex, speed, mtu) + ret[name] = _common.snicstats(isup, duplex, speed, mtu, '') return ret diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py index e130c935..d6b7a21a 100755 --- a/psutil/tests/test_system.py +++ b/psutil/tests/test_system.py @@ -808,12 +808,13 @@ class TestNetAPIs(PsutilTestCase): psutil.NIC_DUPLEX_UNKNOWN) for name, stats in nics.items(): self.assertIsInstance(name, str) - isup, duplex, speed, mtu = stats + isup, duplex, speed, mtu, flags = stats self.assertIsInstance(isup, bool) self.assertIn(duplex, all_duplexes) self.assertIn(duplex, all_duplexes) self.assertGreaterEqual(speed, 0) self.assertGreaterEqual(mtu, 0) + self.assertIsInstance(flags, str) @unittest.skipIf(not (LINUX or BSD or MACOS), "LINUX or BSD or MACOS specific") |