-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Rewrite arch/linux #4352
Rewrite arch/linux #4352
Conversation
7afd27b
to
725a8b3
Compare
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## master #4352 +/- ##
==========================================
+ Coverage 82.13% 82.16% +0.02%
==========================================
Files 350 351 +1
Lines 83136 83207 +71
==========================================
+ Hits 68283 68363 +80
+ Misses 14853 14844 -9
|
5234f90
to
b79adc2
Compare
@guedou @p-l- This is ready for review. If you could just try playing around with routes, it would help a lot. Just note an intended change: for IPv4, 'via' and 'default' routes show '0.0.0.0' as the outgoing IP, but that gets resolved properly when calling @evverx Hi ! I was wondering, if you have the time, if it was possible to test this PR with your |
@gpotter2 I cherry-picked the commit on top of my fork and triggered Packit. Looks like the tests passed on all the architectures: https://copr.fedorainfracloud.org/coprs/packit/evverx-scapy-2/build/7329726/. |
Looks like with this PR applied I can see the following log messages in the journal when the test suite is run
I switched back to the master branch, ran the tests and the logs disappeared. |
b79adc2
to
9fab3ca
Compare
Thanks a lot. This should be fixes in the latest version. |
/packit build |
No config file for packit (e.g. For more info, please check out the documentation or contact the Packit team. You can also use our CLI command |
2 similar comments
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
This rewrites much of the arch/linux code, in order to use a RTNETLINK socket instead of reading /proc/net/XXX. Among those: - the read_routes(6) functions - the linux interfaces provider - arch/linux util functions This adds support for multiple IPv4 addresses to interfaces, among with a generally much better handling of routes. fixes secdev#4201
9fab3ca
to
4093936
Compare
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.
Awesome PR! Thanks a lot for made it happen. I bet that it will also speed up loading Scapy on systems with many routes.
What's the minimal kernel version that is needed for this PR to work?
So just a heads up: I'm really not sure this speeds up loading. It gives a much more more accurate result on my machine and in several test setups I tried, but I haven't tested it on a machine that has a billion routes, or similar. I'm not really sure how it performs on those, so maybe it would be a good idea to try that out.
|
I tried to load 1000 routes using the following shell and Python scripts, and got the following error: bash bench_load_prefixes.sh
gpotter2/rewrite-linux-arch 1000
9
real 0m1.848s
user 0m0.766s
sys 0m0.389s
root@vagrant:/vagrant# vim bench_load_prefixes.sh
root@vagrant:/vagrant# bash bench_load_prefixes.sh
gpotter2/rewrite-linux-arch 10000
Traceback (most recent call last):
File "/vagrant/test_routes_loading.py", line 1, in <module>
from scapy.all import *
File "/vagrant/scapy/all.py", line 26, in <module>
from scapy.route import *
File "/vagrant/scapy/route.py", line 222, in <module>
conf.route = Route()
^^^^^^^
File "/vagrant/scapy/route.py", line 37, in __init__
self.resync()
File "/vagrant/scapy/route.py", line 47, in resync
self.routes = read_routes()
^^^^^^^^^^^^^
File "/vagrant/scapy/arch/linux/rtnetlink.py", line 796, in read_routes
results = _read_routes(socket.AF_INET)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/vagrant/scapy/arch/linux/rtnetlink.py", line 772, in _read_routes
results = _sr1_rtrequest(
^^^^^^^^^^^^^^^
File "/vagrant/scapy/arch/linux/rtnetlink.py", line 647, in _sr1_rtrequest
msgs = rtmsghdrs(sock.recv(65535))
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/vagrant/scapy/base_classes.py", line 398, in __call__
i.__init__(*args, **kargs)
File "/vagrant/scapy/packet.py", line 183, in __init__
self.dissect(_pkt)
File "/vagrant/scapy/packet.py", line 1076, in dissect
s = self.do_dissect(s)
^^^^^^^^^^^^^^^^^^
File "/vagrant/scapy/packet.py", line 1014, in do_dissect
s, fval = f.getfield(self, s)
^^^^^^^^^^^^^^^^^^^
File "/vagrant/scapy/fields.py", line 1843, in getfield
raise MaximumItemsCount(
scapy.fields.MaximumItemsCount: Maximum amount of items reached in PacketListField: 100 (defaults to conf.max_list_count)
real 0m1.329s
user 0m0.542s
sys 0m0.260s Setting the value of You can put random IPv4 prefixes into prefixes.txt.gz or populate it from real ones (as I did). cat bench_load_prefixes.sh
N=1000
for PREFIX in $(zcat prefixes.txt.gz |head -n $N)
do
sudo ip route add $PREFIX dev eth0
done
echo $(git branch --show-current) $N
time python3 test_routes_loading.py
for PREFIX in $(zcat prefixes.txt.gz |head -n $N)
do
sudo ip route del $PREFIX dev eth0
done from scapy.all import *
print(len(conf.route.routes)) |
Empirical benchmarks show similar results (i.e. 2s to 5s loading time) between master and this PR. However, for approximately 50000 routes, master loads in 7s while this PR loads in 41s. I was not expecting this PR to be slower when dealing with more routes. I did the test on Ubuntu 23.10 with kernel 6.5.0-15-generic. |
I expected that, we're popping a socket and parsing several messages instead of simply opening a file descriptor and parsing some text. That being said, it's the only way of solving the 'how do you not load the BGP table' problem. And I think that it's not realistic to have 50k routes in main/local. |
f4cf043
to
7161b13
Compare
This is fixed. @guedou Do you agree with my reasoning regarding the slowdowns? |
I was getting this error after secdev#4352 was merged: ``` File "/usr/lib/python3.11/site-packages/scapy/layers/snmp.py", line 20, in <module> from scapy.layers.inet import UDP, IP, ICMP File "/usr/lib/python3.11/site-packages/scapy/layers/inet.py", line 20, in <module> from scapy.ansmachine import AnsweringMachine File "/usr/lib/python3.11/site-packages/scapy/ansmachine.py", line 20, in <module> from scapy.arch import get_if_addr File "/usr/lib/python3.11/site-packages/scapy/arch/__init__.py", line 189, in <module> _set_conf_sockets() # Apply config ^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/config.py", line 826, in _set_conf_sockets conf.ifaces.reload() File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 253, in reload self._reload_provs() File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 249, in _reload_provs self._load(prov.reload(), prov) ^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 51, in reload return self.load() ^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/__init__.py", line 173, in load for iface in _get_if_list().values(): ^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/rtnetlink.py", line 790, in _get_if_list results = _sr1_rtrequest( ^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/rtnetlink.py", line 718, in _sr1_rtrequest sock.setsockopt(SOL_NETLINK, NETLINK_EXT_ACK, 1) OSError: [Errno 92] Protocol not available ```
I was getting this error after secdev#4352 was merged on a linux system with a pretty old kernel (3.10.0-1160.45.1.el7.x86_64): ``` File "/usr/lib/python3.11/site-packages/scapy/layers/snmp.py", line 20, in <module> from scapy.layers.inet import UDP, IP, ICMP File "/usr/lib/python3.11/site-packages/scapy/layers/inet.py", line 20, in <module> from scapy.ansmachine import AnsweringMachine File "/usr/lib/python3.11/site-packages/scapy/ansmachine.py", line 20, in <module> from scapy.arch import get_if_addr File "/usr/lib/python3.11/site-packages/scapy/arch/__init__.py", line 189, in <module> _set_conf_sockets() # Apply config ^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/config.py", line 826, in _set_conf_sockets conf.ifaces.reload() File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 253, in reload self._reload_provs() File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 249, in _reload_provs self._load(prov.reload(), prov) ^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 51, in reload return self.load() ^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/__init__.py", line 173, in load for iface in _get_if_list().values(): ^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/rtnetlink.py", line 790, in _get_if_list results = _sr1_rtrequest( ^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/rtnetlink.py", line 718, in _sr1_rtrequest sock.setsockopt(SOL_NETLINK, NETLINK_EXT_ACK, 1) OSError: [Errno 92] Protocol not available ```
I was getting this error after secdev#4352 was merged on a linux system with a pretty old kernel (3.10.0-1160.45.1.el7.x86_64): ``` File "/usr/lib/python3.11/site-packages/scapy/layers/snmp.py", line 20, in <module> from scapy.layers.inet import UDP, IP, ICMP File "/usr/lib/python3.11/site-packages/scapy/layers/inet.py", line 20, in <module> from scapy.ansmachine import AnsweringMachine File "/usr/lib/python3.11/site-packages/scapy/ansmachine.py", line 20, in <module> from scapy.arch import get_if_addr File "/usr/lib/python3.11/site-packages/scapy/arch/__init__.py", line 189, in <module> _set_conf_sockets() # Apply config ^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/config.py", line 826, in _set_conf_sockets conf.ifaces.reload() File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 253, in reload self._reload_provs() File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 249, in _reload_provs self._load(prov.reload(), prov) ^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 51, in reload return self.load() ^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/__init__.py", line 173, in load for iface in _get_if_list().values(): ^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/rtnetlink.py", line 790, in _get_if_list results = _sr1_rtrequest( ^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/rtnetlink.py", line 718, in _sr1_rtrequest sock.setsockopt(SOL_NETLINK, NETLINK_EXT_ACK, 1) OSError: [Errno 92] Protocol not available ```
I was getting this error after secdev#4352 was merged on a linux system with a pretty old kernel (3.10.0-1160.45.1.el7.x86_64): ``` File "/usr/lib/python3.11/site-packages/scapy/layers/snmp.py", line 20, in <module> from scapy.layers.inet import UDP, IP, ICMP File "/usr/lib/python3.11/site-packages/scapy/layers/inet.py", line 20, in <module> from scapy.ansmachine import AnsweringMachine File "/usr/lib/python3.11/site-packages/scapy/ansmachine.py", line 20, in <module> from scapy.arch import get_if_addr File "/usr/lib/python3.11/site-packages/scapy/arch/__init__.py", line 189, in <module> _set_conf_sockets() # Apply config ^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/config.py", line 826, in _set_conf_sockets conf.ifaces.reload() File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 253, in reload self._reload_provs() File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 249, in _reload_provs self._load(prov.reload(), prov) ^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/interfaces.py", line 51, in reload return self.load() ^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/__init__.py", line 173, in load for iface in _get_if_list().values(): ^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/rtnetlink.py", line 790, in _get_if_list results = _sr1_rtrequest( ^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/site-packages/scapy/arch/linux/rtnetlink.py", line 718, in _sr1_rtrequest sock.setsockopt(SOL_NETLINK, NETLINK_EXT_ACK, 1) OSError: [Errno 92] Protocol not available ```
This rewrites most of the arch/linux code that handles the loading of
conf.ifaces
,conf.route
andconf.route6
, in order to use a RTNETLINK socket (instead of the current reading of/proc/net/XXX
).Among those:
This:
fixes #4201
closes #3275
(maybe other issues too?)
Note to all maintainers
This has been tested on 32 big endian architecture thanks to the folks at packit. (woooo)
This might need thorough TESTING on other platforms (that we don't include in the CI). I hope I didn't break anything on *BSD.