Using namespaces

The code to init a netlink socket in a network namespace was moved to the library core. To run a socket within a netns, simply pass netns argument to the socket init:

import asyncio

from pyroute2 import AsyncIPRoute


async def main():
    async with AsyncIPRoute(netns="test") as ipr:
        print(f"current netns: {ipr.status['netns']}")

asyncio.run(main())
current netns: test

It is possible to use the old NetNS class, it is now just a compatibility wrapper for the new API:

from pyroute2 import NetNS

with NetNS("test") as ns:
    print(f"current netns: {ns.status['netns']}")
current netns: test

Flags also might be used with any constructor. The default flags are os.O_CREAT, which means that the network namespace will be created if doesn't exist. Using 0 as flags value means that the constructor will fail, if the network namespace doesn't exist already:

from pyroute2 import IPRoute

try:
    ipr = IPRoute(netns="foo", flags=0)
except FileNotFoundError:
    print("netns doesn't exist, refuse to start")
netns doesn't exist, refuse to start

The init routine works now as follows:

  • fork a child using multiprocessing

  • start a socket in the child

  • send the socket FD back to the parent

  • init a socket in the parent using the FD from the child

  • exit the child

pyroute2.netlink.core: netns_main(...)
119async def netns_main(ctl, nsname, flags, libc, cls):
120    # A simple child process
121    #
122    payload = None
123    fds = None
124    try:
125        # 1. set network namespace
126        setns(nsname, flags=flags, libc=libc)
127        # 2. start the socket object
128        s = cls()
129        await s.ensure_socket()
130        payload = {}
131        fds = [s.socket.fileno()]
132    except Exception as e:
133        # get class name
134        payload = {'name': e.__class__.__name__, 'args': e.args}
135        fds = []
136    finally:
137        # 3. send the feedback
138        socket.send_fds(ctl, [json.dumps(payload).encode('utf-8')], fds, 1)