Skip to content

Commit

Permalink
core: Merge pull request #1234 from svinota/1226-netns-flags
Browse files Browse the repository at this point in the history
* respect the flags
* respect the libc argument

Bug-Url: #1234
  • Loading branch information
svinota authored Jan 8, 2025
2 parents c1c871a + 1ccb582 commit 44aa658
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 14 deletions.
54 changes: 40 additions & 14 deletions pyroute2/netlink/core.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import asyncio
import builtins
import collections
import errno
import json
import logging
import multiprocessing
import os
Expand Down Expand Up @@ -114,21 +116,31 @@ def datagram_received(self, data, addr):
self.enqueue(data, addr)


async def netns_main(ctl, nsname, cls):
async def netns_main(ctl, nsname, flags, libc, cls):
# A simple child process
#
# 1. set network namespace
setns(nsname)
# 2. start the socket object
s = cls()
await s.ensure_socket()
# 3. send back the file descriptor
socket.send_fds(ctl, [b'test'], [s.socket.fileno()], 1)
payload = None
fds = None
try:
# 1. set network namespace
setns(nsname, flags=flags, libc=libc)
# 2. start the socket object
s = cls()
await s.ensure_socket()
payload = {}
fds = [s.socket.fileno()]
except Exception as e:
# get class name
payload = {'name': e.__class__.__name__, 'args': e.args}
fds = []
finally:
# 3. send the feedback
socket.send_fds(ctl, [json.dumps(payload).encode('utf-8')], fds, 1)
# 4. exit


def netns_init(ctl, nsname, cls):
asyncio.run(netns_main(ctl, nsname, cls))
def netns_init(ctl, nsname, flags, libc, cls):
asyncio.run(netns_main(ctl, nsname, flags, libc, cls))


class AsyncCoreSocket:
Expand Down Expand Up @@ -241,12 +253,26 @@ async def ensure_socket(self):
ctrl = socket.socketpair()
nsproc = multiprocessing.Process(
target=netns_init,
args=(ctrl[0], self.spec['netns'], type(self)),
args=(
ctrl[0],
self.spec['netns'],
self.spec['flags'],
self.libc,
type(self),
),
)
nsproc.start()
(_, (self.local.fileno,), _, _) = socket.recv_fds(
ctrl[1], 1024, 1
)
(data, fds, _, _) = socket.recv_fds(ctrl[1], 1024, 1)
# load the feedback
payload = json.loads(data.decode('utf-8'))
if payload:
if set(payload.keys()) != set(('name', 'args')):
raise TypeError('error loading netns feedback')
error_class = getattr(builtins, payload['name'])
if not issubclass(error_class, Exception):
raise TypeError('error loading netns error')
raise error_class(*payload['args'])
self.local.fileno = fds[0]
nsproc.join()
# 8<-----------------------------------------
self.local.socket = await self.setup_socket()
Expand Down
36 changes: 36 additions & 0 deletions tests/test_linux/test_ipr/test_netns.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,46 @@
import ctypes
import errno
import os

import pytest
from pr2test.marks import require_root

from pyroute2 import NetNS

pytestmark = [require_root()]


def test_flags(context):
nsname = context.new_nsname
with pytest.raises(FileNotFoundError) as e:
NetNS(nsname, flags=0)
assert e.value.args[0] == errno.ENOENT
# 8<-----------------------------------------------------
ns = NetNS(nsname, flags=os.O_CREAT)
assert len([x.get('index') for x in ns.link('dump')]) > 0
ns.close()
# 8<-----------------------------------------------------
ns = NetNS(nsname, flags=0)
assert len([x.get('index') for x in ns.link('dump')]) > 0
ns.close()


def test_libc_id(context):
libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
nsname = context.new_nsname
ns = NetNS(nsname, libc=libc)
assert id(ns.asyncore.libc) == id(libc)
ns.close()


def test_libc_fail_string(context):
nsname = context.new_nsname
with pytest.raises(AttributeError):
# if we pass a string instead of a libc object, the
# libc.mount() must fail with AttributeError
NetNS(nsname, libc='nonsense')


def test_get_netns_info(context):
nsname = context.new_nsname
peer_name = context.new_ifname
Expand Down

0 comments on commit 44aa658

Please sign in to comment.