brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · 1c2408e Raw
175 lines · python
1# SPDX-License-Identifier: GPL-2.02# Copyright (c) 2020 SUSE LLC.3 4import collections5import functools6import json7import os8import socket9import subprocess10import unittest11 12 13# Add the source tree of bpftool and /usr/local/sbin to PATH14cur_dir = os.path.dirname(os.path.realpath(__file__))15bpftool_dir = os.path.abspath(os.path.join(cur_dir, "..", "..", "..", "..",16                                           "tools", "bpf", "bpftool"))17os.environ["PATH"] = bpftool_dir + ":/usr/local/sbin:" + os.environ["PATH"]18 19 20class IfaceNotFoundError(Exception):21    pass22 23 24class UnprivilegedUserError(Exception):25    pass26 27 28def _bpftool(args, json=True):29    _args = ["bpftool"]30    if json:31        _args.append("-j")32    _args.extend(args)33 34    return subprocess.check_output(_args)35 36 37def bpftool(args):38    return _bpftool(args, json=False).decode("utf-8")39 40 41def bpftool_json(args):42    res = _bpftool(args)43    return json.loads(res)44 45 46def get_default_iface():47    for iface in socket.if_nameindex():48        if iface[1] != "lo":49            return iface[1]50    raise IfaceNotFoundError("Could not find any network interface to probe")51 52 53def default_iface(f):54    @functools.wraps(f)55    def wrapper(*args, **kwargs):56        iface = get_default_iface()57        return f(*args, iface, **kwargs)58    return wrapper59 60DMESG_EMITTING_HELPERS = [61        "bpf_probe_write_user",62        "bpf_trace_printk",63        "bpf_trace_vprintk",64    ]65 66class TestBpftool(unittest.TestCase):67    @classmethod68    def setUpClass(cls):69        if os.getuid() != 0:70            raise UnprivilegedUserError(71                "This test suite needs root privileges")72 73    @default_iface74    def test_feature_dev_json(self, iface):75        unexpected_helpers = DMESG_EMITTING_HELPERS76        expected_keys = [77            "syscall_config",78            "program_types",79            "map_types",80            "helpers",81            "misc",82        ]83 84        res = bpftool_json(["feature", "probe", "dev", iface])85        # Check if the result has all expected keys.86        self.assertCountEqual(res.keys(), expected_keys)87        # Check if unexpected helpers are not included in helpers probes88        # result.89        for helpers in res["helpers"].values():90            for unexpected_helper in unexpected_helpers:91                self.assertNotIn(unexpected_helper, helpers)92 93    def test_feature_kernel(self):94        test_cases = [95            bpftool_json(["feature", "probe", "kernel"]),96            bpftool_json(["feature", "probe"]),97            bpftool_json(["feature"]),98        ]99        unexpected_helpers = DMESG_EMITTING_HELPERS100        expected_keys = [101            "syscall_config",102            "system_config",103            "program_types",104            "map_types",105            "helpers",106            "misc",107        ]108 109        for tc in test_cases:110            # Check if the result has all expected keys.111            self.assertCountEqual(tc.keys(), expected_keys)112            # Check if unexpected helpers are not included in helpers probes113            # result.114            for helpers in tc["helpers"].values():115                for unexpected_helper in unexpected_helpers:116                    self.assertNotIn(unexpected_helper, helpers)117 118    def test_feature_kernel_full(self):119        test_cases = [120            bpftool_json(["feature", "probe", "kernel", "full"]),121            bpftool_json(["feature", "probe", "full"]),122        ]123        expected_helpers = DMESG_EMITTING_HELPERS124 125        for tc in test_cases:126            # Check if expected helpers are included at least once in any127            # helpers list for any program type. Unfortunately we cannot assume128            # that they will be included in all program types or a specific129            # subset of programs. It depends on the kernel version and130            # configuration.131            found_helpers = False132 133            for helpers in tc["helpers"].values():134                if all(expected_helper in helpers135                       for expected_helper in expected_helpers):136                    found_helpers = True137                    break138 139            self.assertTrue(found_helpers)140 141    def test_feature_kernel_full_vs_not_full(self):142        full_res = bpftool_json(["feature", "probe", "full"])143        not_full_res = bpftool_json(["feature", "probe"])144        not_full_set = set()145        full_set = set()146 147        for helpers in full_res["helpers"].values():148            for helper in helpers:149                full_set.add(helper)150 151        for helpers in not_full_res["helpers"].values():152            for helper in helpers:153                not_full_set.add(helper)154 155        self.assertCountEqual(full_set - not_full_set,156                              set(DMESG_EMITTING_HELPERS))157        self.assertCountEqual(not_full_set - full_set, set())158 159    def test_feature_macros(self):160        expected_patterns = [161            r"/\*\*\* System call availability \*\*\*/",162            r"#define HAVE_BPF_SYSCALL",163            r"/\*\*\* eBPF program types \*\*\*/",164            r"#define HAVE.*PROG_TYPE",165            r"/\*\*\* eBPF map types \*\*\*/",166            r"#define HAVE.*MAP_TYPE",167            r"/\*\*\* eBPF helper functions \*\*\*/",168            r"#define HAVE.*HELPER",169            r"/\*\*\* eBPF misc features \*\*\*/",170        ]171 172        res = bpftool(["feature", "probe", "macros"])173        for pattern in expected_patterns:174            self.assertRegex(res, pattern)175