diff --git a/docs/index.rst b/docs/index.rst index c6d42c7be..025203dfa 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -735,7 +735,12 @@ 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``). + - **flags**: a string of comma-separated flags on the interface (may be the 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). Example: @@ -750,7 +755,7 @@ Network .. versionchanged:: 5.7.3 `isup` on UNIX also checks whether the NIC is running. - .. versionchanged:: 5.9.1 *flags* field was added. + .. versionchanged:: 5.9.1 *flags* field was added on POSIX. Sensors ------- diff --git a/psutil/_psaix.py b/psutil/_psaix.py index 6e4a475ac..2391478c6 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, None) + ret[name] = _common.snicstats(isup, duplex, speed, mtu, output_flags) return ret diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index feb95e9c0..4a02c8314 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -390,13 +390,8 @@ def net_if_stats(): else: if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) - 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 + 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 4ac2112ad..1991af78e 100644 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -1070,7 +1070,7 @@ def net_if_stats(): debug(err) else: output_flags = ','.join(flags) - isup = 'running' in output_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 9aebdf974..d5cbd8a01 100644 --- a/psutil/_psosx.py +++ b/psutil/_psosx.py @@ -273,7 +273,7 @@ def net_if_stats(): if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) output_flags = ','.join(flags) - isup = 'running' in output_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 701471383..541c1aa4a 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, None) + ret[name] = _common.snicstats(isup, duplex, speed, mtu, '') return ret diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c index 877e81375..ddc3d6b89 100644 --- a/psutil/_psutil_posix.c +++ b/psutil/_psutil_posix.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -429,6 +430,24 @@ psutil_net_if_mtu(PyObject *self, PyObject *args) { return PyErr_SetFromErrno(PyExc_OSError); } +static bool +check_and_append_iff_flag(PyObject *py_retlist, short int flags, short int flag_to_check, const char * flag_name) +{ + PyObject *py_str = NULL; + + if (flags & flag_to_check) { + py_str = PyUnicode_DecodeFSDefault(flag_name); + if (! py_str) + return false; + if (PyList_Append(py_retlist, py_str)) { + Py_DECREF(py_str); + return false; + } + Py_CLEAR(py_str); + } + + return true; +} /* * Get all of the NIC flags and return them. @@ -440,89 +459,151 @@ psutil_net_if_flags(PyObject *self, PyObject *args) { 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; + goto error; sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock == -1) - return NULL; + if (sock == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } PSUTIL_STRNCPY(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); ret = ioctl(sock, SIOCGIFFLAGS, &ifr); - if (ret == -1) + if (ret == -1) { + PyErr_SetFromErrno(PyExc_OSError); 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; - } + // 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 (!check_and_append_iff_flag(py_retlist, flags, IFF_UP, "up")) + goto error; +#endif +#ifdef IFF_BROADCAST + // Available in (at least) Linux, macOS, AIX, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_BROADCAST, "broadcast")) + goto error; +#endif +#ifdef IFF_DEBUG + // Available in (at least) Linux, macOS, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_DEBUG, "debug")) + goto error; +#endif +#ifdef IFF_LOOPBACK + // Available in (at least) Linux, macOS, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_LOOPBACK, "loopback")) + goto error; +#endif +#ifdef IFF_POINTOPOINT + // Available in (at least) Linux, macOS, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_POINTOPOINT, "pointopoint")) + goto error; +#endif +#ifdef IFF_NOTRAILERS + // Available in (at least) Linux, macOS, AIX + if (!check_and_append_iff_flag(py_retlist, flags, IFF_NOTRAILERS, "notrailers")) + goto error; +#endif +#ifdef IFF_RUNNING + // Available in (at least) Linux, macOS, AIX, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_RUNNING, "running")) + goto error; +#endif +#ifdef IFF_NOARP + // Available in (at least) Linux, macOS, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_NOARP, "noarp")) + goto error; +#endif +#ifdef IFF_PROMISC + // Available in (at least) Linux, macOS, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_PROMISC, "promisc")) + goto error; +#endif +#ifdef IFF_ALLMULTI + // Available in (at least) Linux, macOS, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_ALLMULTI, "allmulti")) + goto error; +#endif +#ifdef IFF_MASTER + // Available in (at least) Linux + if (!check_and_append_iff_flag(py_retlist, flags, IFF_MASTER, "master")) + goto error; +#endif +#ifdef IFF_SLAVE + // Available in (at least) Linux + if (!check_and_append_iff_flag(py_retlist, flags, IFF_SLAVE, "slave")) + goto error; +#endif +#ifdef IFF_MULTICAST + // Available in (at least) Linux, macOS, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_MULTICAST, "multicast")) + goto error; +#endif +#ifdef IFF_PORTSEL + // Available in (at least) Linux + if (!check_and_append_iff_flag(py_retlist, flags, IFF_PORTSEL, "portsel")) + goto error; +#endif +#ifdef IFF_AUTOMEDIA + // Available in (at least) Linux + if (!check_and_append_iff_flag(py_retlist, flags, IFF_AUTOMEDIA, "automedia")) + goto error; +#endif +#ifdef IFF_DYNAMIC + // Available in (at least) Linux + if (!check_and_append_iff_flag(py_retlist, flags, IFF_DYNAMIC, "dynamic")) + goto error; +#endif +#ifdef IFF_OACTIVE + // Available in (at least) macOS, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_OACTIVE, "oactive")) + goto error; +#endif +#ifdef IFF_SIMPLEX + // Available in (at least) macOS, AIX, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_SIMPLEX, "simplex")) + goto error; +#endif +#ifdef IFF_LINK0 + // Available in (at least) macOS, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_LINK0, "link0")) + goto error; +#endif +#ifdef IFF_LINK1 + // Available in (at least) macOS, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_LINK1, "link1")) + goto error; +#endif +#ifdef IFF_LINK2 + // Available in (at least) macOS, BSD + if (!check_and_append_iff_flag(py_retlist, flags, IFF_LINK2, "link2")) + goto error; +#endif +#ifdef IFF_D2 + // Available in (at least) AIX + if (!check_and_append_iff_flag(py_retlist, flags, IFF_D2, "d2")) + goto error; +#endif return py_retlist; error: - Py_XDECREF(py_flag); Py_DECREF(py_retlist); if (sock != -1) close(sock); diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 57ace466b..7d882b774 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, None) + ret[name] = _common.snicstats(isup, duplex, speed, mtu, '') return ret