svinota / pyroute2

Python Netlink and PF_ROUTE library — network configuration and monitoring
https://pyroute2.org/
Other
959 stars 248 forks source link

Cannot get multipath nexthops for route in netns #1026

Open tobias-urdin opened 2 years ago

tobias-urdin commented 2 years ago
import pyroute2
with pyroute2.NetNS("test") as netns:
        routes = netns.route('get', dst=destination)
        for route in routes:
            #print(route.multipath) <-- does not exist
            #route only has one RTA_GATEWAY attr

I've tried using dump API instead and use a match function but no luck there either. How can I reproduce the behaviour of ip route show <prefix> or maybe ip route get <ip> fibmatch? Dumping all routes and parsing probably doesn't help either and there is a lot of routes so it would take too long time.

svinota commented 2 years ago
routes = netns.route('dump', dst=destination)
for route in routes:
    print(route)
    hops = route.get('multipath')
    for hop in hops:
        print(hop)
        print(hop.get('gateway'))

Regarding get <ip> fibmatch — thanks for the hint, I'll take a look, and will add if not implemented

tobias-urdin commented 2 years ago

Thanks I was digging a lot to try to find how to get that. I guess the version in Ubuntu 18.04.1 LTS is to old python3-pyroute2 0.4.21-0.1ubuntu2 to get that info thought?

root@router:~# ip route show 164.100.0.0/27
164.100.0.0/27 proto bgp metric 20 
    nexthop via 10.0.0.9 dev enp101s0f1 weight 1 
    nexthop via 10.0.0.10 dev enp101s0f0 weight 1 

When I use dump though, it pretty much just hangs (consider the whole internet routing table), even if dump should do a get when dst is set in route() IIRC when checking code earlier.

So this one, never completes, I ^C after a minute:

import pyroute2

ipr = pyroute2.IPRoute()
routes = ipr.route('dump', dst='164.100.0.0/27')

for route in routes:
    print(route)
    hops = route.get('multipath')
    print(hops)

Using get I get a result but not containing those multipath nexthops just the RTA_GATEWAY

import pyroute2

ipr = pyroute2.IPRoute()
routes = ipr.route('get', dst='164.100.0.0/27')

for route in routes:
    print(route)
    hops = route.get('multipath')
    print(hops)
{'family': 2, 'dst_len': 32, 'src_len': 0, 'tos': 0, 'table': 254, 'proto': 0, 'scope': 0, 'type': 1, 'flags': 512, 'attrs': [('RTA_TABLE', 254), ('RTA_DST', '164.100.0.0'), ('RTA_OIF', 7), ('RTA_PREFSRC', '10.0.0.9'), ('RTA_GATEWAY', '10.0.0.10'), ('UNKNOWN', {'header': {'length': 8, 'type': 25}}), ('RTA_CACHEINFO', {'rta_clntref': 2, 'rta_lastuse': 0, 'rta_expires': 0, 'rta_error': 0, 'rta_used': 0, 'rta_id': 0, 'rta_ts': 0, 'rta_tsage': 0})], 'header': {'length': 112, 'type': 24, 'flags': 0, 'sequence_number': 255, 'pid': 31787, 'error': None}, 'event': 'RTM_NEWROUTE'}
None

So the get is essentially ip route get 164.100.0.0 which would only return one of the nexthops in RTA_GATEWAY. I guess I might be out of luck here with the version?

svinota commented 2 years ago

Yep, 'cause get never returns the original route record from the table, but instead a routing info that actually will be used for one packet — it's always one nexthop.

Dumping the whole table takes a while, to say the list, since the parser is not the best in the terms of the performance.

Starting from version 0.4.3 the library has an API to write & use a custom parser (say, to run a binary match against the data buffers knowing the offsets, and parse only the matching messages), that may significantly speed up dumps in some situations.

And give me a day or two to investigate this fibmatch.

jvgutierrez commented 6 months ago

@svinota any progress on fibmatch support?