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
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)