-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add in support for network interface flags. #2037
Add in support for network interface flags. #2037
Conversation
These flags are pretty useless since there are no exposed constants to compare them against (
...similarly to
What makes me skeptical about this is that most of the flags above seem to refer to the network interface itself, and not the individual addresses. E.g. associating "IFF_PROMISC", "IFF_PORTSEL" or "IFF_AUTOMEDIA" to a network address wouldn't make much sense. As such, perhaps the right place to do this is |
That's fine by me. I'll go ahead and implement it that way instead.
OK, that sounds good to me as well. I'll add a new extension API for getting the flags and add it to the |
And this has all been done in b75a234. Please take a look when you get a chance. |
I've now rebased this onto the latest, and resolved the conflicts in HISTORY.rst based on the release. This is ready for another review when you have time. |
Rebased onto the latest again. Please take a look. |
Friendly ping on this one; do you think we could get this in? |
Hi Chris and sorry for being late but life got busier. =) I re-read your patch and I'm happy to include this functionality. I don't like hard-coding C constants in python though. I prefer if that is done in C. I remember we do something like this in here: Line 730 in df3fba5
I guess you can do something like that and remove "," at the beginning/end of the resulting string if needed.
|
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]>
Thanks for the feedback. I went through and rewrote most of it in C, but in a slightly different way (see 1a5842b). In particular, what I'm doing there is constructing a list of strings to return to the Python layer, which I can then easily combine using By the way, it turns out that it is much, much better to do this at the C layer. The |
docs/index.rst
Outdated
|
||
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- .. versionchanged:: 5.9.1 *flags* field was added.
+ .. versionchanged:: 5.9.1 *flags* field was added on POSIX.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in e05f926.
docs/index.rst
Outdated
@@ -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``). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I think an empty string is better than None. This way anybody can do
if "running" in flags
without pre-emptively checkingif flag is not None
. - please also list all the possible strings values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to an empty string everywhere below. Also listed all of the possible string values in e05f926.
psutil/_psaix.py
Outdated
@@ -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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since psutil_net_if_is_running
function was already working on AIX / SunOS, I guess you can enable this code on those platforms as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've enabled it for AIX, as it is basically the same code. That said, I don't have access to an AIX machine, so I can't verify it there.
See my comment below about SunOS.
psutil/_psbsd.py
Outdated
flag_list = [] | ||
for flagname, bit in _psposix.POSIX_NET_FLAGS: | ||
if flags & (1 << bit): | ||
flag_list.append(flagname) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dead code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, good call. Removed in e05f926.
psutil/_psutil_posix.c
Outdated
|
||
sock = socket(AF_INET, SOCK_DGRAM, 0); | ||
if (sock == -1) | ||
return NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should add PyErr_SetFromErrno(PyExc_OSError);
, then goto error;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in e05f926.
psutil/_pswindows.py
Outdated
@@ -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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's return ""
instead of None
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in e05f926.
psutil/_psbsd.py
Outdated
if flags & (1 << bit): | ||
flag_list.append(flagname) | ||
|
||
output_flags = ','.join(flag_list) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please rename this variable to just flags
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I kept this as output_flags
currently, as we still need to use flags
for the list of flags. I'm happy to change the name of both if you want, just let me know what you would prefer.
@@ -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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please rename this variable to just flags
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here.
@@ -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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please rename this variable to just flags
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here.
psutil/_pssunos.py
Outdated
@@ -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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's enable this on sunos as well (see my previous comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So SunOS is a completely different beast than Linux, BSD, macOS, or Windows. Looking at the code in
Line 1484 in 4446e3b
psutil_net_if_stats(PyObject* self, PyObject* args) { |
ioctl
(it is using something called SIOCGLIFFLAGS), and then it verifies that data with another structure (kstat?). So I don't think I can easily enable SunOS, and I don't have access to a SunOS machine.
Signed-off-by: Chris Lalancette <[email protected]>
@giampaolo Thanks for the very detailed review! I've made a number of changes based on your review, though I opted not to make some of the changes you requested (individual comments have details why). Please take another look! |
docs/index.rst
Outdated
@@ -735,20 +735,28 @@ 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 the empty string). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"may be AN empty string"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in d83c959.
docs/index.rst
Outdated
|
||
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 on POSIX. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5.9.2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in d83c959.
} | ||
|
||
return true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like doing the flag comparison / check in here (if flags & flag_to_check ...
). That should happen in the main function. The utility function (this one) should only add the item to the dict.
Also, instead of return true
or false
I would just return 1
or 0
_, which is consistent with the rest of the code base and avoids including <stdbool.h>
(I have some memories of this header file causing problems on some platform).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair. I've switched this helper function to return an int, and I'm now doing the check in the main function. All in d83c959.
psutil/_psutil_posix.c
Outdated
|
||
sock = socket(AF_INET, SOCK_DGRAM, 0); | ||
if (sock == -1) { | ||
PyErr_SetFromErrno(PyExc_OSError); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use PyErr_SetFromOSErrnoWithSyscall("socket(SOCK_DGRAM)");
.
Since in this function we can fail for 2 different reasons, this will tell where the error originated from (socket() instead of ioctl()).
(sorry, I know I told you to PyErr_SetFromErrno
use this but I forgot we have PyErr_SetFromOSErrnoWithSyscall
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem, it happens. Fixed in d83c959.
psutil/_psutil_posix.c
Outdated
PSUTIL_STRNCPY(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); | ||
ret = ioctl(sock, SIOCGIFFLAGS, &ifr); | ||
if (ret == -1) { | ||
PyErr_SetFromErrno(PyExc_OSError); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use PyErr_SetFromOSErrnoWithSyscall("ioctl(SIOCGIFFLAGS)");
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in d83c959.
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add:
self.assertIsInstance(flags, str)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in d83c959.
Signed-off-by: Chris Lalancette <[email protected]>
Sorry for the delay here (I was on vacation). I've now gone through and fixed up all of the latest issues; please take another look! |
``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). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add . Availability: POSIX
. After merge I'll try to take a look on how feasible it is to do this on Windows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added it in 3082526 . Let me know if that is where you want it.
docs/index.rst
Outdated
|
||
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.2 *flags* field was added on POSIX. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I released 5.9.2 yesterday. Please set this to 5.9.3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 3082526
psutil/_psutil_posix.c
Outdated
@@ -9,6 +9,7 @@ | |||
#include <Python.h> | |||
#include <errno.h> | |||
#include <stdlib.h> | |||
#include <stdbool.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can remove this, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call, removed in 3082526
I added some final comments but overall it's good to go. |
Signed-off-by: Chris Lalancette <[email protected]>
Thanks! Besides your comments, I also made small changes in 3082526 that should hopefully make linting happier. |
Perfect. I'm happy with this change. Thanks. |
Thank you so much! I appreciate all of the good feedback and the merge of the PR. |
Summary
Description
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.
I was careful to add the
flags
field to the end of thesnicaddr
named tuple so that the API wouldn't be broken.Full disclosure: I've tested this on Linux and on macOS, and it seems to work OK on both of those. I have not tested on Windows, since I don't have a Windows machine handy.
I've made a few choices here that we could change:
net_if_addrs()
as opposed tonet_if_stats()
or adding a new API. That makes the most sense to me, but I'm happy to change it if you feel otherwise.getifaddrs()
on POSIX. The meaning of each of the bits is standardized by POSIX, so it should be the same on all platforms that support this. That said, we could make this "nicer" and possibly more Pythonic by expanding those bitfields into human-readable flags.Signed-off-by: Chris Lalancette [email protected]