Skip to content

Commit 1a5842b

Browse files
committed
Add in support for network interface flags.
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]>
1 parent df3fba5 commit 1a5842b

13 files changed

+135
-15
lines changed

CREDITS

+4
Original file line numberDiff line numberDiff line change
@@ -789,3 +789,7 @@ I: 2099
789789

790790
N: Torsten Blum
791791
I: 2114
792+
793+
N: Chris Lalancette
794+
W: https://github.com/clalancette
795+
I: 2037

HISTORY.rst

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
- 1053_: drop Python 2.6 support. (patches by Matthieu Darbois and Hugo van
1616
Kemenade)
17+
- 2037_: Add additional flags to net_if_stats.
1718
- 2050_, [Linux]: increase ``read(2)`` buffer size from 1k to 32k when reading
1819
``/proc`` pseudo files line by line. This should help having more consistent
1920
results.

README.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,8 @@ Network
252252
snicaddr(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
253253
>>>
254254
>>> psutil.net_if_stats()
255-
{'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536),
256-
'wlan0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500)}
255+
{'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536, flags='up,loopback,running'),
256+
'wlan0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500, flags='up,broadcast,running,multicast')}
257257
>>>
258258
259259
Sensors

docs/index.rst

+5-2
Original file line numberDiff line numberDiff line change
@@ -735,20 +735,23 @@ Network
735735
- **speed**: the NIC speed expressed in mega bits (MB), if it can't be
736736
determined (e.g. 'localhost') it will be set to ``0``.
737737
- **mtu**: NIC's maximum transmission unit expressed in bytes.
738+
- **flags**: a string of comma-separate flags on the interface (may be ``None``).
738739

739740
Example:
740741

741742
>>> import psutil
742743
>>> psutil.net_if_stats()
743-
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
744-
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
744+
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500, flags='up,broadcast,running,multicast'),
745+
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536, flags='up,loopback,running')}
745746

746747
Also see `nettop.py`_ and `ifconfig.py`_ for an example application.
747748

748749
.. versionadded:: 3.0.0
749750

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

753+
.. versionchanged:: 5.9.1 *flags* field was added.
754+
752755
Sensors
753756
-------
754757

psutil/_common.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ class BatteryTime(enum.IntEnum):
199199
snicaddr = namedtuple('snicaddr',
200200
['family', 'address', 'netmask', 'broadcast', 'ptp'])
201201
# psutil.net_if_stats()
202-
snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])
202+
snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu', 'flags'])
203203
# psutil.cpu_stats()
204204
scpustats = namedtuple(
205205
'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls'])

psutil/_psaix.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ def net_if_stats():
258258
duplex = re_result.group(2)
259259

260260
duplex = duplex_map.get(duplex, NIC_DUPLEX_UNKNOWN)
261-
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
261+
ret[name] = _common.snicstats(isup, duplex, speed, mtu, None)
262262
return ret
263263

264264

psutil/_psbsd.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ def net_if_stats():
381381
for name in names:
382382
try:
383383
mtu = cext_posix.net_if_mtu(name)
384-
isup = cext_posix.net_if_is_running(name)
384+
flags = cext_posix.net_if_flags(name)
385385
duplex, speed = cext_posix.net_if_duplex_speed(name)
386386
except OSError as err:
387387
# https://github.com/giampaolo/psutil/issues/1279
@@ -390,7 +390,14 @@ def net_if_stats():
390390
else:
391391
if hasattr(_common, 'NicDuplex'):
392392
duplex = _common.NicDuplex(duplex)
393-
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
393+
flag_list = []
394+
for flagname, bit in _psposix.POSIX_NET_FLAGS:
395+
if flags & (1 << bit):
396+
flag_list.append(flagname)
397+
398+
output_flags = ','.join(flag_list)
399+
isup = 'running' in output_flags
400+
ret[name] = _common.snicstats(isup, duplex, speed, mtu, output_flags)
394401
return ret
395402

396403

psutil/_pslinux.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,7 @@ def net_if_stats():
10601060
for name in names:
10611061
try:
10621062
mtu = cext_posix.net_if_mtu(name)
1063-
isup = cext_posix.net_if_is_running(name)
1063+
flags = cext_posix.net_if_flags(name)
10641064
duplex, speed = cext.net_if_duplex_speed(name)
10651065
except OSError as err:
10661066
# https://github.com/giampaolo/psutil/issues/1279
@@ -1069,7 +1069,9 @@ def net_if_stats():
10691069
else:
10701070
debug(err)
10711071
else:
1072-
ret[name] = _common.snicstats(isup, duplex_map[duplex], speed, mtu)
1072+
output_flags = ','.join(flags)
1073+
isup = 'running' in output_flags
1074+
ret[name] = _common.snicstats(isup, duplex_map[duplex], speed, mtu, output_flags)
10731075
return ret
10741076

10751077

psutil/_psosx.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ def net_if_stats():
263263
for name in names:
264264
try:
265265
mtu = cext_posix.net_if_mtu(name)
266-
isup = cext_posix.net_if_is_running(name)
266+
flags = cext_posix.net_if_flags(name)
267267
duplex, speed = cext_posix.net_if_duplex_speed(name)
268268
except OSError as err:
269269
# https://github.com/giampaolo/psutil/issues/1279
@@ -272,7 +272,9 @@ def net_if_stats():
272272
else:
273273
if hasattr(_common, 'NicDuplex'):
274274
duplex = _common.NicDuplex(duplex)
275-
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
275+
output_flags = ','.join(flags)
276+
isup = 'running' in output_flags
277+
ret[name] = _common.snicstats(isup, duplex, speed, mtu, output_flags)
276278
return ret
277279

278280

psutil/_pssunos.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ def net_if_stats():
293293
isup, duplex, speed, mtu = items
294294
if hasattr(_common, 'NicDuplex'):
295295
duplex = _common.NicDuplex(duplex)
296-
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
296+
ret[name] = _common.snicstats(isup, duplex, speed, mtu, None)
297297
return ret
298298

299299

psutil/_psutil_posix.c

+101
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,106 @@ psutil_net_if_mtu(PyObject *self, PyObject *args) {
430430
}
431431

432432

433+
/*
434+
* Get all of the NIC flags and return them.
435+
*/
436+
static PyObject *
437+
psutil_net_if_flags(PyObject *self, PyObject *args) {
438+
char *nic_name;
439+
int sock = -1;
440+
int ret;
441+
struct ifreq ifr;
442+
PyObject *py_retlist = PyList_New(0);
443+
PyObject *py_flag = NULL;
444+
short int flags;
445+
446+
if (py_retlist == NULL)
447+
return NULL;
448+
449+
if (! PyArg_ParseTuple(args, "s", &nic_name))
450+
return NULL;
451+
452+
sock = socket(AF_INET, SOCK_DGRAM, 0);
453+
if (sock == -1)
454+
return NULL;
455+
456+
PSUTIL_STRNCPY(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
457+
ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
458+
if (ret == -1)
459+
goto error;
460+
461+
close(sock);
462+
sock = -1;
463+
464+
flags = ifr.ifr_flags & 0xFFFF;
465+
466+
if (flags & IFF_UP) {
467+
py_flag = PyUnicode_DecodeFSDefault("up");
468+
if (PyList_Append(py_retlist, py_flag))
469+
goto error;
470+
}
471+
if (flags & IFF_BROADCAST) {
472+
py_flag = PyUnicode_DecodeFSDefault("broadcast");
473+
if (PyList_Append(py_retlist, py_flag))
474+
goto error;
475+
}
476+
if (flags & IFF_DEBUG) {
477+
py_flag = PyUnicode_DecodeFSDefault("debug");
478+
if (PyList_Append(py_retlist, py_flag))
479+
goto error;
480+
}
481+
if (flags & IFF_LOOPBACK) {
482+
py_flag = PyUnicode_DecodeFSDefault("loopback");
483+
if (PyList_Append(py_retlist, py_flag))
484+
goto error;
485+
}
486+
if (flags & IFF_POINTOPOINT) {
487+
py_flag = PyUnicode_DecodeFSDefault("pointopoint");
488+
if (PyList_Append(py_retlist, py_flag))
489+
goto error;
490+
}
491+
if (flags & IFF_NOTRAILERS) {
492+
py_flag = PyUnicode_DecodeFSDefault("notrailers");
493+
if (PyList_Append(py_retlist, py_flag))
494+
goto error;
495+
}
496+
if (flags & IFF_RUNNING) {
497+
py_flag = PyUnicode_DecodeFSDefault("running");
498+
if (PyList_Append(py_retlist, py_flag))
499+
goto error;
500+
}
501+
if (flags & IFF_NOARP) {
502+
py_flag = PyUnicode_DecodeFSDefault("noarp");
503+
if (PyList_Append(py_retlist, py_flag))
504+
goto error;
505+
}
506+
if (flags & IFF_PROMISC) {
507+
py_flag = PyUnicode_DecodeFSDefault("promisc");
508+
if (PyList_Append(py_retlist, py_flag))
509+
goto error;
510+
}
511+
if (flags & IFF_ALLMULTI) {
512+
py_flag = PyUnicode_DecodeFSDefault("allmulti");
513+
if (PyList_Append(py_retlist, py_flag))
514+
goto error;
515+
}
516+
if (flags & IFF_MULTICAST) {
517+
py_flag = PyUnicode_DecodeFSDefault("multicast");
518+
if (PyList_Append(py_retlist, py_flag))
519+
goto error;
520+
}
521+
522+
return py_retlist;
523+
524+
error:
525+
Py_XDECREF(py_flag);
526+
Py_DECREF(py_retlist);
527+
if (sock != -1)
528+
close(sock);
529+
return NULL;
530+
}
531+
532+
433533
/*
434534
* Inspect NIC flags, returns a bool indicating whether the NIC is
435535
* running. References:
@@ -667,6 +767,7 @@ static PyMethodDef mod_methods[] = {
667767
{"getpagesize", psutil_getpagesize_pywrapper, METH_VARARGS},
668768
{"getpriority", psutil_posix_getpriority, METH_VARARGS},
669769
{"net_if_addrs", psutil_net_if_addrs, METH_VARARGS},
770+
{"net_if_flags", psutil_net_if_flags, METH_VARARGS},
670771
{"net_if_is_running", psutil_net_if_is_running, METH_VARARGS},
671772
{"net_if_mtu", psutil_net_if_mtu, METH_VARARGS},
672773
{"setpriority", psutil_posix_setpriority, METH_VARARGS},

psutil/_pswindows.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ def net_if_stats():
386386
isup, duplex, speed, mtu = items
387387
if hasattr(_common, 'NicDuplex'):
388388
duplex = _common.NicDuplex(duplex)
389-
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
389+
ret[name] = _common.snicstats(isup, duplex, speed, mtu, None)
390390
return ret
391391

392392

psutil/tests/test_system.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ def test_net_if_stats(self):
808808
psutil.NIC_DUPLEX_UNKNOWN)
809809
for name, stats in nics.items():
810810
self.assertIsInstance(name, str)
811-
isup, duplex, speed, mtu = stats
811+
isup, duplex, speed, mtu, flags = stats
812812
self.assertIsInstance(isup, bool)
813813
self.assertIn(duplex, all_duplexes)
814814
self.assertIn(duplex, all_duplexes)

0 commit comments

Comments
 (0)