svinota / pyroute2

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

NDB register_handler #897

Open carloslockward opened 2 years ago

carloslockward commented 2 years ago

I'm trying to detect when a network change has occurred(change of state, change of ip addres/routes, etc.). With IPDB one would use the register_callback method to listen for this types of changes.

Because IPDB is deprecated im trying to do something similar using NDB's register_handler method but I cant get it to work(the register_handler method returns with no problem but the callbacks never happen.) and there appears to be no docs about this particular feature.

Attempts

>>> from pyroute2.ndb import events
>>> from pyroute2.ndb.events import State
>>>
>>> ndb.register_handler(State, do_this)
>>> ndb.register_handler(cmsg_event, do_this)
>>> ndb.register_handler("RTM_NEWROUTE", do_this)

Notes

svinota commented 2 years ago

My bad.

The method ndb.register_handler() takes two parameters:

  1. A message class to react on
  2. A callback to run when reacting

The callback must take two parameters: target and event, where target is the system where the event comes from (localhost, or a netns, or …).

Right now you can play with that using:

# it is important to use import from pr2modules here, since the NDB
# event sources emit messages with this signature
from pr2modules.netlink.rtnl.ifinfmsg import ifinfmsg
from pyroute2 import NDB

def test_handler(target, event):
    print(target, event)

ndb = NDB(log="debug")
ndb.register_handler(ifinfmsg, test_handler)
…
# run outside:
# sudo ip link add dev test type dummy

Another approach may be:

interface = ndb.interfaces.wait(ifname="test")
address = ndb.addresses.wait(index=interface["index"])

The API here is not complete yet (register_handler() is an internal method and must have some friendly alternative that will not require users to do any imports) and barely documented, so thanks for pointing that out — I'm to fix that asap.

carloslockward commented 2 years ago

Thanks for the clarification!

When implementing the new friendlier alternative to this method. Consider having the event msg be on a friendlier format similar to whats provided by NDB if posible. For now I use this functionality as is and will translate the event msg to a dict manually.

Thanks!

svinota commented 2 years ago

A good point, thanks.

carloslockward commented 2 years ago

@svinota I have been trying to use this but i still haven't completely figured it out.

I want to basically listen for changes on the configuration of a specific interface. Using ndb.register_handler(ifinfmsg, test_handler) like you suggested does capture RTM_NEWLINK events, but not RTM_NEWROUTE for example.

I'm also not sure how the wait works.

I would expect that if I run test = ndb.routes.wait(action="add", ifname="enp1s0", timeout=10) code will wait/block until a new route is added and return the newly added route or the timeout is exceeded and returns None. But instead this command just returns another route immediately (not even in the same interface).

So how does the .wait() work exactly? and how could I indefinitely wait for a route to be added? Thanks

gatici commented 3 months ago

Hello @svinota,

We are replacing IPDB with NDB and we tried to use register_handler method from NDB as below.
You can see the PR: https://github.com/omec-project/upf/pull/830/files What I observed, only the RTM_DELLINK and RTM_NEWLINK events are received although other events are triggered such as RTM_NEWNEIGH, RTM_DELROUTE, RTM_NEWROUTE.

The below simple script could be used to see the missing events. If we add some routes, events did not arrive. Could you please guide me to find a solution?

from time import sleep

from pr2modules.netlink.rtnl.ifinfmsg import ifinfmsg
from pyroute2 import NDB

def test_handler(target, event):
    print("target:", target)
    print("event:", event['event'])

ndb = NDB()
ndb.task_manager.register_handler(ifinfmsg, test_handler)
sleep(1000)
gatici commented 3 months ago

Hello @svinota,

We are replacing IPDB with NDB and we tried to use register_handler method from NDB as below. You can see the PR: https://github.com/omec-project/upf/pull/830/files What I observed, only the RTM_DELLINK and RTM_NEWLINK events are received although other events are triggered such as RTM_NEWNEIGH, RTM_DELROUTE, RTM_NEWROUTE.

The below simple script could be used to see the missing events. If we add some routes, events did not arrive. Could you please guide me to find a solution?

from time import sleep

from pr2modules.netlink.rtnl.ifinfmsg import ifinfmsg
from pyroute2 import NDB

def test_handler(target, event):
    print("target:", target)
    print("event:", event['event'])

ndb = NDB()
ndb.task_manager.register_handler(ifinfmsg, test_handler)
sleep(1000)

I found that that different message types needs to be used.

    rtnl.RTM_NEWROUTE: rtmsg,
    rtnl.RTM_DELROUTE: rtmsg,
    rtnl.RTM_NEWNEIGH: ndmsg,