1# 2# Copyright (C) 2020 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16 17import logging 18import re 19 20from proc_tests import KernelProcFileTestBase 21import target_file_utils 22 23 24class ProcQtaguidCtrlTest(KernelProcFileTestBase.KernelProcFileTestBase): 25 '''/proc/net/xt_qtaguid/ctrl provides information about tagged sockets. 26 27 File content consists of possibly several lines of socket info followed by a 28 single line of events info, followed by a terminating newline.''' 29 30 def parse_contents(self, contents): 31 result = [] 32 lines = contents.split('\n') 33 if len(lines) == 0 or lines[-1] != '': 34 raise SyntaxError 35 for line in lines[:-2]: 36 parsed = self.parse_line( 37 "sock={:x} tag=0x{:x} (uid={:d}) pid={:d} f_count={:d}", line) 38 if any(map(lambda x: x < 0, parsed)): 39 raise SyntaxError("Negative numbers not allowed!") 40 result.append(parsed) 41 parsed = self.parse_line( 42 "events: sockets_tagged={:d} sockets_untagged={:d} counter_set_changes={:d} " 43 "delete_cmds={:d} iface_events={:d} match_calls={:d} match_calls_prepost={:d} " 44 "match_found_sk={:d} match_found_sk_in_ct={:d} match_found_no_sk_in_ct={:d} " 45 "match_no_sk={:d} match_no_sk_{:w}={:d}", lines[-2]) 46 if parsed[-2] not in {"file", "gid"}: 47 raise SyntaxError("match_no_sk_{file|gid} incorrect") 48 del parsed[-2] 49 if any(map(lambda x: x < 0, parsed)): 50 raise SyntaxError("Negative numbers not allowed!") 51 result.append(parsed) 52 return result 53 54 def get_path(self): 55 return "/proc/net/xt_qtaguid/ctrl" 56 57 def file_optional(self, shell=None, dut=None): 58 """Specifies if the /proc/net/xt_qtaguid/ctrl file is mandatory. 59 60 For device running kernel 4.9 or above, it should use the eBPF cgroup 61 filter to monitor networking stats instead. So it may not have 62 xt_qtaguid module and /proc/net/xt_qtaguid/ctrl file on device. 63 But for device that still has xt_qtaguid module, this file is mandatory. 64 65 Same logic as checkKernelSupport in file: 66 test/vts-testcase/kernel/api/qtaguid/SocketTagUserSpace.cpp 67 68 Returns: 69 True when the kernel is 4.9 or newer, otherwise False is returned 70 """ 71 (version, patchlevel, sublevel) = self._kernel_version(dut) 72 if version == 4 and patchlevel >= 9 or version > 4: 73 return True 74 else: 75 return False 76 77 def _kernel_version(self, dut): 78 """Gets the kernel version from the device. 79 80 This method reads the output of command "uname -r" from the device. 81 82 Returns: 83 A tuple of kernel version information 84 in the format of (version, patchlevel, sublevel). 85 86 It will fail if failed to get the output or correct format 87 from the output of "uname -r" command 88 """ 89 cmd = 'uname -r' 90 out, _, _ = dut.shell.Execute(cmd) 91 out = out.strip() 92 93 match = re.match(r"(\d+)\.(\d+)\.(\d+)", out) 94 if match is None: 95 raise RuntimeError("Failed to detect kernel version of device. out:%s" % out) 96 97 version = int(match.group(1)) 98 patchlevel = int(match.group(2)) 99 sublevel = int(match.group(3)) 100 logging.info("Detected kernel version: %s", match.group(0)) 101 return (version, patchlevel, sublevel) 102 103 def get_permission_checker(self): 104 """Get r/w file permission checker. 105 """ 106 return target_file_utils.IsReadWrite 107