Commit 97031128 authored by Peter V. Saveliev's avatar Peter V. Saveliev

netns: accept int and fd as arguments to `setns()`

Examples::

	fd = open('/proc/self/ns/net', 'r')
	netns.setns('foo')
	# do something in `foo`
	# … and return back
	netns.setns(fd)
	fd.close()
parent c86432a1
......@@ -83,6 +83,7 @@ import os.path
import errno
import ctypes
from pyroute2 import config
from pyroute2.common import basestring
# FIXME: arch reference
__NR = {'x86_': {'64bit': 308},
......@@ -185,17 +186,25 @@ def setns(netns, flags=os.O_CREAT, libc=None):
- O_CREAT | O_EXCL -- create only if doesn't exist
'''
libc = libc or ctypes.CDLL('libc.so.6', use_errno=True)
netnspath = _get_netnspath(netns)
if os.path.basename(netns) in listnetns(os.path.dirname(netns)):
if flags & (os.O_CREAT | os.O_EXCL) == (os.O_CREAT | os.O_EXCL):
raise OSError(errno.EEXIST, 'netns exists', netns)
if isinstance(netns, basestring):
netnspath = _get_netnspath(netns)
if os.path.basename(netns) in listnetns(os.path.dirname(netns)):
if flags & (os.O_CREAT | os.O_EXCL) == (os.O_CREAT | os.O_EXCL):
raise OSError(errno.EEXIST, 'netns exists', netns)
else:
if flags & os.O_CREAT:
create(netns, libc=libc)
nsfd = os.open(netnspath, os.O_RDONLY)
ret = nsfd
elif isinstance(netns, file):
nsfd = netns.fileno()
ret = netns
elif isinstance(netns, int):
nsfd = netns
ret = netns
else:
if flags & os.O_CREAT:
create(netns, libc=libc)
nsfd = os.open(netnspath, os.O_RDONLY)
ret = libc.syscall(__NR_setns, nsfd, CLONE_NEWNET)
if ret != 0:
raise RuntimeError('netns should be a string or an open fd')
error = libc.syscall(__NR_setns, nsfd, CLONE_NEWNET)
if error != 0:
raise OSError(ctypes.get_errno(), 'failed to open netns', netns)
return nsfd
return ret
......@@ -188,6 +188,27 @@ class TestNetNS(object):
netnsmod.remove(foo)
netnsmod.remove(bar)
def test_there_and_back(self):
require_user('root')
fd = open('/proc/self/ns/net', 'r')
foo = str(uuid4())
#
# please notice, that IPRoute / IPDB, started in a netns, will continue
# to work in a given netns even if the process changes to another netns
#
with IPRoute() as ip:
links_main1 = set([x.get('index', None) for x in ip.get_links()])
netnsmod.setns(foo)
with IPRoute() as ip:
links_foo = set([x.get('index', None) for x in ip.get_links()])
netnsmod.setns(fd)
with IPRoute() as ip:
links_main2 = set([x.get('index', None) for x in ip.get_links()])
assert links_main1 == links_main2
assert links_main1 != links_foo
netnsmod.remove(foo)
fd.close()
def test_move_ns_fd(self):
foo = str(uuid4())
bar = str(uuid4())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment