• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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