Skip to content

Commit

Permalink
Add in support for network interface flags.
Browse files Browse the repository at this point in the history
That is, return the raw flag integer as reported by getifaddrs()
on POSIX-compatible systems.  On Windows systems (and any other
ones that do not support flags), return None instead.

Signed-off-by: Chris Lalancette <[email protected]>
  • Loading branch information
clalancette committed Aug 16, 2022
1 parent df3fba5 commit 1a5842b
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 15 deletions.
4 changes: 4 additions & 0 deletions CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -789,3 +789,7 @@ I: 2099

N: Torsten Blum
I: 2114

N: Chris Lalancette
W: https://github.com/clalancette
I: 2037
1 change: 1 addition & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -735,20 +735,23 @@ 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=<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.

.. versionadded:: 3.0.0

.. versionchanged:: 5.7.3 `isup` on UNIX also checks whether the NIC is running.

.. versionchanged:: 5.9.1 *flags* field was added.

Sensors
-------

Expand Down
2 changes: 1 addition & 1 deletion psutil/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'])
Expand Down
2 changes: 1 addition & 1 deletion psutil/_psaix.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
11 changes: 9 additions & 2 deletions psutil/_psbsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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


Expand Down
6 changes: 4 additions & 2 deletions psutil/_pslinux.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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


Expand Down
6 changes: 4 additions & 2 deletions psutil/_psosx.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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


Expand Down
2 changes: 1 addition & 1 deletion psutil/_pssunos.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
101 changes: 101 additions & 0 deletions psutil/_psutil_posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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},
Expand Down
2 changes: 1 addition & 1 deletion psutil/_pswindows.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
2 changes: 1 addition & 1 deletion psutil/tests/test_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 1a5842b

Please sign in to comment.