NDB module intro

NDB is a high level network management module. IT allows to manage interfaces, routes, addresses etc. of connected systems, containers and network namespaces.

In a nutshell, NDB collects and aggregates netlink events in an SQL database, provides Python objects to reflect the system state, and applies changes back to the system. The database expects updates only from the sources, no manual SQL updates are expected normally.

_images/aafig-80bc0b850cd3f4d027d8d72e97c7fc1b52fe5bca.svg

object names on the diagram are clickable

The goal of NDB is to provide an easy access to RTNL info and entities via Python objects, like pyroute2.ndb.objects.interface (see also: Network interfaces), pyroute2.ndb.objects.route (see also: Routes management) etc. These objects do not only reflect the system state for the time of their instantiation, but continuously monitor the system for relevant updates. The monitoring is done via netlink notifications, thus no polling. Also the objects allow to apply changes back to the system and rollback the changes.

On the other hand it’s too expensive to create Python objects for all the available RTNL entities, e.g. when there are hundreds of interfaces and thousands of routes. Thus NDB creates objects only upon request, when the user calls .create() to create new objects or runs ndb.<view>[selector] (e.g. ndb.interfaces[‘eth0’]) to access an existing object.

To list existing RTNL entities NDB uses objects of the class RecordSet that yield individual Record objects for every entity (see also: Record list filters). An object of the Record class is immutable, doesn’t monitor any updates, doesn’t contain any links to other objects and essentially behaves like a simple named tuple.

_images/aafig-db02be09e1d33d12b493455bdfd27b7ad0692510.svg

object names on the diagram are clickable

Here are some simple NDB usage examples. More info see in the reference documentation below.

Print all the interface names on the system, assume we have an NDB instance ndb:

for interface in ndb.interfaces.dump():
    print(interface.ifname)
lo
eth0

Print the routing information in the CSV format:

for record in ndb.routes.summary().format('csv'):
    print(record)
'target','tflags','table','ifname','dst','dst_len','gateway'
'localhost',0,254,'eth0','',0,'192.168.122.1'
'localhost',0,254,'eth0','192.168.122.0',24,
'localhost',0,255,'lo','127.0.0.0',8,
'localhost',0,255,'lo','127.0.0.1',32,
'localhost',0,255,'lo','127.255.255.255',32,
'localhost',0,255,'eth0','192.168.122.28',32,
'localhost',0,255,'eth0','192.168.122.255',32,

Note

More on report filtering and formatting: Record list filters

Print IP addresses of interfaces in several network namespaces as:

nslist = ['netns01',
          'netns02',
          'netns03']

for nsname in nslist:
    ndb.sources.add(netns=nsname)

report = ndb.addresses.summary()
report.select_records(target=lambda x: x.startswith('netns'))
report.select_fields('address', 'ifname', 'target')
for line in report.format('json'):
    print(line)
[
    {
        "address": "127.0.0.1",
        "ifname": "lo",
        "target": "netns01"
    },
    {
        "address": "127.0.0.1",
        "ifname": "lo",
        "target": "netns02"
    },
    {
        "address": "127.0.0.1",
        "ifname": "lo",
        "target": "netns03"
    }
]

Add an IP address on an interface:

with ndb.interfaces['eth0'] as eth0:
    eth0.add_ip('10.0.0.1/24')
# ---> <---  NDB waits until the address setup

Change an interface property:

with ndb.interfaces['eth0'] as eth0:
    eth0.set(
        state='up',
        address='00:11:22:33:44:55',
    )
# ---> <---  NDB waits here for the changes to be applied
#            the commit() is called automatically by the
#            context manager's __exit__()

NDB reference