diff options
author | dennishan <dennishan@realtek.com> | 2020-06-08 19:01:42 +0800 |
---|---|---|
committer | Maciej Żenczykowski <maze@google.com> | 2020-06-09 20:49:06 +0000 |
commit | 73cf98163867a226979341760ff42c82d608b11c (patch) | |
tree | aacfc971950269e36988d5a3df82ba5c16ad2a46 | |
parent | d8385e2e7f732a73e9fe9130d3a974d1254681d1 (diff) | |
download | kernel_tests-73cf98163867a226979341760ff42c82d608b11c.tar.gz kernel_tests-73cf98163867a226979341760ff42c82d608b11c.tar.bz2 kernel_tests-73cf98163867a226979341760ff42c82d608b11c.zip |
net-test: attempt to use namespaces on devices with ADB/TCP
Update all_tests.py and add namespace.py from master branch.
Bug: 149894399
Test: run vts -m VtsKernelNetTest -s 192.168.1.100:5555
Change-Id: I00829029fea63a58a548455ed2edcbd7c5ae2b62
Merged-In: I2e5d136322ade41bfefcb46437b61a68fb842e15
-rwxr-xr-x | net/test/all_tests.py | 20 | ||||
-rw-r--r-- | net/test/namespace.py | 165 |
2 files changed, 181 insertions, 4 deletions
diff --git a/net/test/all_tests.py b/net/test/all_tests.py index bbef3ac4..17d9701d 100755 --- a/net/test/all_tests.py +++ b/net/test/all_tests.py @@ -14,10 +14,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from importlib import import_module +import importlib import sys import unittest +import namespace + test_modules = [ 'anycast_test', 'bpf_test', @@ -46,15 +48,25 @@ test_modules = [ ] if __name__ == '__main__': + # Check whether ADB over TCP is occupying TCP port 5555. + if namespace.HasEstablishedTcpSessionOnPort(5555): + namespace.IfPossibleEnterNewNetworkNamespace() # First, run InjectTests on all modules, to ensure that any parameterized # tests in those modules are injected. for name in test_modules: - import_module(name) - if hasattr(sys.modules[name], "InjectTests"): + importlib.import_module(name) + if hasattr(sys.modules[name], 'InjectTests'): sys.modules[name].InjectTests() loader = unittest.defaultTestLoader - test_suite = loader.loadTestsFromNames(test_modules) + if len(sys.argv) > 1: + test_suite = loader.loadTestsFromNames(sys.argv[1:]) + else: + test_suite = loader.loadTestsFromNames(test_modules) + + assert test_suite.countTestCases() > 0, ( + 'Inconceivable: no tests found! Command line: %s' % ' '.join(sys.argv)) + runner = unittest.TextTestRunner(verbosity=2) result = runner.run(test_suite) sys.exit(not result.wasSuccessful()) diff --git a/net/test/namespace.py b/net/test/namespace.py new file mode 100644 index 00000000..85db6541 --- /dev/null +++ b/net/test/namespace.py @@ -0,0 +1,165 @@ +#!/usr/bin/python +# +# Copyright 2020 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Namespace related support code.""" + +import ctypes +import ctypes.util +import os +import socket + +import net_test +import sock_diag +import tcp_test + +# //include/linux/fs.h +MNT_FORCE = 1 # Attempt to forcibily umount +MNT_DETACH = 2 # Just detach from the tree +MNT_EXPIRE = 4 # Mark for expiry +UMOUNT_NOFOLLOW = 8 # Don't follow symlink on umount + +# //include/uapi/linux/fs.h +MS_RDONLY = 1 # Mount read-only +MS_NOSUID = 2 # Ignore suid and sgid bits +MS_NODEV = 4 # Disallow access to device special files +MS_NOEXEC = 8 # Disallow program execution +MS_SYNCHRONOUS = 16 # Writes are synced at once +MS_REMOUNT = 32 # Alter flags of a mounted FS +MS_MANDLOCK = 64 # Allow mandatory locks on an FS +MS_DIRSYNC = 128 # Directory modifications are synchronous +MS_NOATIME = 1024 # Do not update access times. +MS_NODIRATIME = 2048 # Do not update directory access times +MS_BIND = 4096 # +MS_MOVE = 8192 # +MS_REC = 16384 # +MS_SILENT = 32768 # +MS_POSIXACL = (1<<16) # VFS does not apply the umask +MS_UNBINDABLE = (1<<17) # change to unbindable +MS_PRIVATE = (1<<18) # change to private +MS_SLAVE = (1<<19) # change to slave +MS_SHARED = (1<<20) # change to shared +MS_RELATIME = (1<<21) # Update atime relative to mtime/ctime. +MS_STRICTATIME = (1<<24) # Always perform atime updates +MS_LAZYTIME = (1<<25) # Update the on-disk [acm]times lazily + +# //include/uapi/linux/sched.h +CLONE_NEWNS = 0x00020000 # New mount namespace group +CLONE_NEWCGROUP = 0x02000000 # New cgroup namespace +CLONE_NEWUTS = 0x04000000 # New utsname namespace +CLONE_NEWIPC = 0x08000000 # New ipc namespace +CLONE_NEWUSER = 0x10000000 # New user namespace +CLONE_NEWPID = 0x20000000 # New pid namespace +CLONE_NEWNET = 0x40000000 # New network namespace + +libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True) + +# See the relevant system call's man pages and: +# https://docs.python.org/3/library/ctypes.html#fundamental-data-types +libc.mount.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, + ctypes.c_ulong, ctypes.c_void_p) +libc.sethostname.argtype = (ctypes.c_char_p, ctypes.c_size_t) +libc.umount2.argtypes = (ctypes.c_char_p, ctypes.c_int) +libc.unshare.argtypes = (ctypes.c_int,) + + +def Mount(src, tgt, fs, flags=MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_RELATIME): + ret = libc.mount(src, tgt, fs, flags, None) + if ret < 0: + errno = ctypes.get_errno() + raise OSError(errno, '%s mounting %s on %s (fs=%s flags=0x%x)' + % (os.strerror(errno), src, tgt, fs, flags)) + + +def ReMountProc(): + libc.umount2('/proc', MNT_DETACH) # Ignore failure: might not be mounted + Mount('proc', '/proc', 'proc') + + +def ReMountSys(): + libc.umount2('/sys', MNT_DETACH) # Ignore failure: might not be mounted + Mount('sysfs', '/sys', 'sysfs') + + +def SetFileContents(f, s): + open(f, 'w').write(s) + + +def SetHostname(s): + ret = libc.sethostname(s, len(s)) + if ret < 0: + errno = ctypes.get_errno() + raise OSError(errno, '%s while sethostname(%s)' % (os.strerror(errno), s)) + + +def UnShare(flags): + ret = libc.unshare(flags) + if ret < 0: + errno = ctypes.get_errno() + raise OSError(errno, '%s while unshare(0x%x)' % (os.strerror(errno), flags)) + + +def DumpMounts(hdr): + print + print hdr + print open('/proc/mounts', 'r').read(), + print '---' + + +# Requires at least kernel configuration options: +# CONFIG_NAMESPACES=y +# CONFIG_NET_NS=y +# CONFIG_UTS_NS=y +def IfPossibleEnterNewNetworkNamespace(): + """Instantiate and transition into a fresh new network namespace if possible.""" + + print 'Creating clean namespace...', + + try: + UnShare(CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWNET) + except OSError as err: + print 'failed: %s (likely: no privs or lack of kernel support).' % err + return False + + try: + # DumpMounts('Before:') + Mount('none', '/', None, MS_REC|MS_PRIVATE) + ReMountProc() + ReMountSys() + # DumpMounts('After:') + SetHostname('netns') + SetFileContents('/proc/sys/net/ipv4/ping_group_range', '0 2147483647') + net_test.SetInterfaceUp('lo') + except: + print 'failed.' + # We've already transitioned into the new netns -- it's too late to recover. + raise + + print 'succeeded.' + return True + + +def HasEstablishedTcpSessionOnPort(port): + sd = sock_diag.SockDiag() + + sock_id = sd._EmptyInetDiagSockId() + sock_id.sport = port + + states = 1 << tcp_test.TCP_ESTABLISHED + + matches = sd.DumpAllInetSockets(socket.IPPROTO_TCP, "", + sock_id=sock_id, states=states) + + return len(matches) > 0 |