Search code examples
pythonnetlinkiproute

Retrieving the netnsid of a network namespace in Python


When trying to find the correct peer network interface of a veth pair that lives in a different namespace, that end is not only indicated by its iflink property, but also by a link-netnsid. This link-netnsid is a network namespace ID which is only meaningful within the current network namespace.

The Linux kernel doesn't offer to map a netnsid to a network namespace inode number, which is the only unique identification. However, Linux offers the RTM_GETNSID request that maps a network namespace identified either by fd (NETNSA_FD) or by PID (NETNSA_PID) to the local netnsid.

How do I make such a RTM_GETNSID request in Python, preferably using the pyroute2 library? So far, I could not successfully request the netnsid for the namespace identified by PID, but only get back an invalid argument error 22, using the following script:

from pyroute2 import IPRoute
from pyroute2.netlink import NLM_F_REQUEST
import pyroute2.netlink.rtnl as rtnl
import pyroute2.netlink.rtnl.nsidmsg as nsidmsg

netstack = IPRoute()
req = nsidmsg.nsidmsg()
req['rtgen_family'] = 0
# 12345 is PID of a process inside another network namespace
req['attrs'] = [('NETNSA_PID', 12345)]
ret = netstack.nlm_request(req, rtnl.RTM_GETNSID, NLM_F_REQUEST)

Solution

  • It turns out that my code actually is correct, but there's a bug in pyroute2 causing the RTNETLINK message to be a few octets too short (visible in strace). As a temporary hack around this library bug it is sufficient to set two attributes, so that the kernel accepts the RTNETLINK packet and works on it, even if it isn't fully correct.

    from pyroute2 import IPRoute
    from pyroute2.netlink import NLM_F_REQUEST
    import pyroute2.netlink.rtnl as rtnl
    import pyroute2.netlink.rtnl.nsidmsg as nsidmsg
    
    netstack = IPRoute()
    req = nsidmsg.nsidmsg()
    req['rtgen_family'] = 0
    # 12345 is PID of a process inside another network namespace
    req['attrs'] = [('NETNSA_PID', 12345), ('NETNSA_PID', 0]  # hack around pyroute 0.5.0 bug
    ret = netstack.nlm_request(req, rtnl.RTM_GETNSID, NLM_F_REQUEST)