It is easy to start to develop with pyroute2. In the simplest case one just uses the library as is, and please do not forget to file issues, bugs and feature requests to the project github page.

If something should be changed in the library itself, and you think you can do it, this document should help a bit.

Modules layout

The library consists of several significant parts, and every part has its own functionality:

NetlinkSocket: connects the library to the OS
  ↑       ↑
  |       |
  |       ↓
  |     Marshal ←—→ Message classes
  |
  |
  ↓
NL utility classes: more or less user-friendly API

NetlinkSocket and Marshal: Base netlink socket and marshal

NetlinkSocket

Notice, that it is possible to use a custom base class instead of socket.socket. Thus, one can transparently port this library to any different transport, or to use it with eventlet library, that is not happy with socket.socket objects, and so on.

Marshal

A custom marshalling class can be required, if the protocol uses some different marshalling algo from usual netlink. Otherwise it is enough to use register_policy method of the NetlinkSocket:

# somewhere in a custom netlink class

# dict key: message id, int
# dict value: message class
policy = {IPSET_CMD_PROTOCOL: ipset_msg,
          IPSET_CMD_LIST: ipset_msg}

def __init__(self, ...):
    ...
    self.register_policy(policy)

But if just matching is not enough, refer to the Marshal implementation. It is possible, e.g., to define the custom fix_message method to be run on every message, etc. A sample of such custom marshal can be found in the RTNL implementation: pyroute2.netlink.rtnl.

Messages

All the message classes hierarchy is built on the simple fact that the netlink message structure is recursive in that or other way.

A usual way to implement messages is described in the netlink docs: Netlink basics.

The core module, pyroute2.netlink, provides base classes nlmsg and nla, as well as some other (genlmsg), and basic NLA types: uint32, be32, ip4addr, l2addr etc.

One of the NLA types, hex, can be used to dump the NLA structure in the hex format – it is useful for development.

NL utility classes

They are based on different netlink sockets, such as IPRsocket (RTNL), NL80211 (wireless), or just NetlinkSocket – be it generic netlink or nfnetlink (see taskstats and ipset).

Primarily, pyroute2 is a netlink framework, so basic classes and low-level utilities are intended to return parsed netlink messages, not some user-friendly output. So be not surprised.

But user-friendly modules are also possible and partly provided, such as IPDB.

A list of low-level utility classes:

  • IPRoute [pyroute2.iproute], RTNL utility like ip/tc
  • IPSet [pyroute2.ipset], manipulate IP sets
  • IW [pyroute2.iwutil], basic nl80211 support
  • NetNS [pyroute2.netns], netns-enabled IPRoute
  • TaskStats [pyroute2.netlink.taskstats], taskstats utility

High-level utilities:

  • IPDB [pyroute2.ipdb], async IP database

Deferred imports

The file pyroute2/__init__.py is a proxy for some modules, thus providing a fixed import address, like:

from pyroute2 import IPRoute
ipr = IPRoute()
...
ipr.close()

But not only. Actually, pyroute2/__init__.py exports not classes and modules, but proxy objects, that load the actual code in the runtime. The rationale is simple: in that way we provide a possibility to use a custom base classes, see examples/custom_socket_base.py.

Protocol debugging

The simplest way to start with some netlink protocol is to use a reference implementation. Lets say we wrote the ipset_msg class using the kernel code, and want to check how it works. So the ipset(8) utility will be used as a reference implementation:

$ sudo strace -e trace=network -f -x -s 4096 ipset list
socket(PF_NETLINK, SOCK_RAW, NETLINK_NETFILTER) = 3
bind(3, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0
getsockname(3, {sa_family=AF_NETLINK, pid=7009, groups=00000000}, [12]) = 0
sendto(3, "\x1c\x00\x00\x00\x01\x06\x01\x00\xe3\x95\...
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000},
    msg_iov(1)=[{"\x1c\x00\x00\x00\x01\x06\x00\x00\xe3\...
sendto(3, "\x1c\x00\x00\x00\x07\x06\x05\x03\xe4\x95\...
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000},
    msg_iov(1)=[{"\x78\x00\x00\x00\x07\x06\x02\x00\xe4\...

Here you can just copy packet strings from sendto and recvmsg, place in a file and use scripts/decoder.py to inspect them:

$ export PYTHONPATH=`pwd`
$ python scripts/decoder.py \
    pyroute2.netlink.nfnetlink.ipset.ipset_msg \
    scripts/ipset_01.data

See collected samples in the scripts directory. The script ignores spaces and allows multiple messages in the same file.

Table Of Contents

Previous topic

Modules in progress

Next topic

Project contribution guide

This Page