diff --git a/CREDITS b/CREDITS index 61e754531..90e127d7e 100644 --- a/CREDITS +++ b/CREDITS @@ -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 d4c68192c..98ff4c1a9 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -14,6 +14,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. diff --git a/README.rst b/README.rst index 0e0a29afd..5f0afcdfa 100644 --- a/README.rst +++ b/README.rst @@ -252,8 +252,8 @@ Network snicaddr(family=, 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=, speed=0, mtu=65536), - 'wlan0': snicstats(isup=True, duplex=, speed=100, mtu=1500)} + {'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536, flags='up,loopback,running'), + 'wlan0': snicstats(isup=True, duplex=, speed=100, mtu=1500, flags='up,broadcast,running,multicast')} >>> Sensors diff --git a/docs/index.rst b/docs/index.rst index 8d663c7ec..c6d42c7be 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -735,13 +735,14 @@ 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-separate flags on the interface (may be ``None``). Example: >>> import psutil >>> psutil.net_if_stats() - {'eth0': snicstats(isup=True, duplex=, speed=100, mtu=1500), - 'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536)} + {'eth0': snicstats(isup=True, duplex=, speed=100, mtu=1500, flags='up,broadcast,running,multicast'), + 'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536, flags='up,loopback,running')} Also see `nettop.py`_ and `ifconfig.py`_ for an example application. @@ -749,6 +750,8 @@ Network .. versionchanged:: 5.7.3 `isup` on UNIX also checks whether the NIC is running. + .. versionchanged:: 5.9.1 *flags* field was added. + Sensors ------- diff --git a/psutil/_common.py b/psutil/_common.py index 9937eb832..2b66019b7 100644 --- a/psutil/_common.py +++ b/psutil/_common.py @@ -199,7 +199,7 @@ class BatteryTime(enum.IntEnum): 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 9cc7d56e3..6e4a475ac 100644 --- a/psutil/_psaix.py +++ b/psutil/_psaix.py @@ -258,7 +258,7 @@ def net_if_stats(): duplex = re_result.group(2) duplex = duplex_map.get(duplex, NIC_DUPLEX_UNKNOWN) - ret[name] = _common.snicstats(isup, duplex, speed, mtu) + ret[name] = _common.snicstats(isup, duplex, speed, mtu, None) return ret diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index 56acedb3a..feb95e9c0 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -381,7 +381,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 @@ -390,7 +390,14 @@ def net_if_stats(): else: if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) - ret[name] = _common.snicstats(isup, duplex, speed, mtu) + flag_list = [] + for flagname, bit in _psposix.POSIX_NET_FLAGS: + if flags & (1 << bit): + flag_list.append(flagname) + + output_flags = ','.join(flag_list) + isup = 'running' in output_flags + ret[name] = _common.snicstats(isup, duplex, speed, mtu, output_flags) return ret diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index e7cef439d..4ac2112ad 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,9 @@ 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 output_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 ac8ecc530..9aebdf974 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,9 @@ 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 output_flags + ret[name] = _common.snicstats(isup, duplex, speed, mtu, output_flags) return ret diff --git a/psutil/_pssunos.py b/psutil/_pssunos.py index 69b579c5f..701471383 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, None) return ret diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c index 045366145..877e81375 100644 --- a/psutil/_psutil_posix.c +++ b/psutil/_psutil_posix.c @@ -430,6 +430,106 @@ psutil_net_if_mtu(PyObject *self, PyObject *args) { } +/* + * 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); + PyObject *py_flag = NULL; + short int flags; + + if (py_retlist == NULL) + return NULL; + + if (! PyArg_ParseTuple(args, "s", &nic_name)) + return NULL; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + return NULL; + + PSUTIL_STRNCPY(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); + ret = ioctl(sock, SIOCGIFFLAGS, &ifr); + if (ret == -1) + goto error; + + close(sock); + sock = -1; + + flags = ifr.ifr_flags & 0xFFFF; + + if (flags & IFF_UP) { + py_flag = PyUnicode_DecodeFSDefault("up"); + if (PyList_Append(py_retlist, py_flag)) + goto error; + } + if (flags & IFF_BROADCAST) { + py_flag = PyUnicode_DecodeFSDefault("broadcast"); + if (PyList_Append(py_retlist, py_flag)) + goto error; + } + if (flags & IFF_DEBUG) { + py_flag = PyUnicode_DecodeFSDefault("debug"); + if (PyList_Append(py_retlist, py_flag)) + goto error; + } + if (flags & IFF_LOOPBACK) { + py_flag = PyUnicode_DecodeFSDefault("loopback"); + if (PyList_Append(py_retlist, py_flag)) + goto error; + } + if (flags & IFF_POINTOPOINT) { + py_flag = PyUnicode_DecodeFSDefault("pointopoint"); + if (PyList_Append(py_retlist, py_flag)) + goto error; + } + if (flags & IFF_NOTRAILERS) { + py_flag = PyUnicode_DecodeFSDefault("notrailers"); + if (PyList_Append(py_retlist, py_flag)) + goto error; + } + if (flags & IFF_RUNNING) { + py_flag = PyUnicode_DecodeFSDefault("running"); + if (PyList_Append(py_retlist, py_flag)) + goto error; + } + if (flags & IFF_NOARP) { + py_flag = PyUnicode_DecodeFSDefault("noarp"); + if (PyList_Append(py_retlist, py_flag)) + goto error; + } + if (flags & IFF_PROMISC) { + py_flag = PyUnicode_DecodeFSDefault("promisc"); + if (PyList_Append(py_retlist, py_flag)) + goto error; + } + if (flags & IFF_ALLMULTI) { + py_flag = PyUnicode_DecodeFSDefault("allmulti"); + if (PyList_Append(py_retlist, py_flag)) + goto error; + } + if (flags & IFF_MULTICAST) { + py_flag = PyUnicode_DecodeFSDefault("multicast"); + if (PyList_Append(py_retlist, py_flag)) + goto error; + } + + return py_retlist; + +error: + Py_XDECREF(py_flag); + Py_DECREF(py_retlist); + if (sock != -1) + close(sock); + return NULL; +} + + /* * Inspect NIC flags, returns a bool indicating whether the NIC is * running. References: @@ -667,6 +767,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 31edffc1c..57ace466b 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, None) return ret diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py index e130c935e..f12d6fb3f 100755 --- a/psutil/tests/test_system.py +++ b/psutil/tests/test_system.py @@ -808,7 +808,7 @@ def test_net_if_stats(self): 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)