svinota / pyroute2

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

IPRoute.get_neighbours remove kwargs #738

Open ffourcot opened 4 years ago

ffourcot commented 4 years ago

Hello,

get_neighbours is defined by a very simple function:

return self.neigh('dump', family=family, match=match or kwarg)

So, kwarg are never given to neigh() method. This has a big side effect, since NLA list building is based only on kwarg, and not on match:

          for key in kwarg:
              nla = ndmsg.ndmsg.name2nla(key)
              if kwarg[key] is not None:
                  msg['attrs'].append([nla, kwarg[key]])

We can compare netlink message generated with both methods:

In [5]: IPRoute().neigh("dump", master=2)  # NDA_MASTER is set, kernel filtering is working!
{'family': <AddressFamily.AF_INET: 2>, '__pad': 0, 'ifindex': 0, 'state': 0, 'flags': 0, 'ndm_type': 0, 'attrs': [('NDA_MASTER', 2)], 'value': <class 'pyroute2.netlink.NotInitialized'>, 'header': {'type': 30, 'flags': 769, 'sequence_number': 255, 'pid': 5741, 'length': 36}}

In [6]: IPRoute().get_neighbours(master=2) # NDA_MASTER is not set! filtering is done only in userspace
{'family': <AddressFamily.AF_INET: 2>, '__pad': 0, 'ifindex': 0, 'state': 0, 'flags': 0, 'ndm_type': 0, 'attrs': [], 'value': <class 'pyroute2.netlink.NotInitialized'>, 'header': {'type': 30, 'flags': 769, 'sequence_number': 255, 'pid': 5741, 'length': 28}}

Out of performance, it does not have any impact. But on arp cache, it's easy to have some performance issue

ljluestc commented 1 year ago
#!/usr/bin/env python3
import pyroute2

class CustomIPRoute(pyroute2.IPRoute):
    def get_neighbours(self, family=None, match=None, **kwargs):
        if match is None:
            match = {}
        match.update(kwargs)
        return self.neigh('dump', family=family, match=match)

def main():
    ip = CustomIPRoute()

    # Example: Get neighbors with a specific master
    neighbors = ip.get_neighbours(master=2)

    for neighbor in neighbors:
        print(neighbor)

if __name__ == '__main__':
    main()