aboutsummaryrefslogtreecommitdiff
path: root/tools/testing/selftests/drivers/net/lib/py/env.py
blob: 579c5b34e6fd6f6b2909f2ee614ba4efed97df99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# SPDX-License-Identifier: GPL-2.0

import os
import shlex
from pathlib import Path
from lib.py import ip
from lib.py import NetNS, NetdevSimDev
from .remote import Remote


def _load_env_file(src_path):
    env = os.environ.copy()

    src_dir = Path(src_path).parent.resolve()
    if not (src_dir / "net.config").exists():
        return env

    lexer = shlex.shlex(open((src_dir / "net.config").as_posix(), 'r').read())
    k = None
    for token in lexer:
        if k is None:
            k = token
            env[k] = ""
        elif token == "=":
            pass
        else:
            env[k] = token
            k = None
    return env


class NetDrvEnv:
    """
    Class for a single NIC / host env, with no remote end
    """
    def __init__(self, src_path):
        self._ns = None

        self.env = _load_env_file(src_path)

        if 'NETIF' in self.env:
            self.dev = ip("link show dev " + self.env['NETIF'], json=True)[0]
        else:
            self._ns = NetdevSimDev()
            self.dev = self._ns.nsims[0].dev
        self.ifindex = self.dev['ifindex']

    def __enter__(self):
        return self

    def __exit__(self, ex_type, ex_value, ex_tb):
        """
        __exit__ gets called at the end of a "with" block.
        """
        self.__del__()

    def __del__(self):
        if self._ns:
            self._ns.remove()
            self._ns = None


class NetDrvEpEnv:
    """
    Class for an environment with a local device and "remote endpoint"
    which can be used to send traffic in.

    For local testing it creates two network namespaces and a pair
    of netdevsim devices.
    """

    # Network prefixes used for local tests
    nsim_v4_pfx = "192.0.2."
    nsim_v6_pfx = "2001:db8::"

    def __init__(self, src_path):

        self.env = _load_env_file(src_path)

        # Things we try to destroy
        self.remote = None
        # These are for local testing state
        self._netns = None
        self._ns = None
        self._ns_peer = None

        if "NETIF" in self.env:
            self.dev = ip("link show dev " + self.env['NETIF'], json=True)[0]

            self.v4 = self.env.get("LOCAL_V4")
            self.v6 = self.env.get("LOCAL_V6")
            self.remote_v4 = self.env.get("REMOTE_V4")
            self.remote_v6 = self.env.get("REMOTE_V6")
            kind = self.env["REMOTE_TYPE"]
            args = self.env["REMOTE_ARGS"]
        else:
            self.create_local()

            self.dev = self._ns.nsims[0].dev

            self.v4 = self.nsim_v4_pfx + "1"
            self.v6 = self.nsim_v6_pfx + "1"
            self.remote_v4 = self.nsim_v4_pfx + "2"
            self.remote_v6 = self.nsim_v6_pfx + "2"
            kind = "netns"
            args = self._netns.name

        self.remote = Remote(kind, args, src_path)

        self.addr = self.v6 if self.v6 else self.v4
        self.remote_addr = self.remote_v6 if self.remote_v6 else self.remote_v4

        self.ifname = self.dev['ifname']
        self.ifindex = self.dev['ifindex']

    def create_local(self):
        self._netns = NetNS()
        self._ns = NetdevSimDev()
        self._ns_peer = NetdevSimDev(ns=self._netns)

        with open("/proc/self/ns/net") as nsfd0, \
             open("/var/run/netns/" + self._netns.name) as nsfd1:
            ifi0 = self._ns.nsims[0].ifindex
            ifi1 = self._ns_peer.nsims[0].ifindex
            NetdevSimDev.ctrl_write('link_device',
                                    f'{nsfd0.fileno()}:{ifi0} {nsfd1.fileno()}:{ifi1}')

        ip(f"   addr add dev {self._ns.nsims[0].ifname} {self.nsim_v4_pfx}1/24")
        ip(f"-6 addr add dev {self._ns.nsims[0].ifname} {self.nsim_v6_pfx}1/64 nodad")
        ip(f"   link set dev {self._ns.nsims[0].ifname} up")

        ip(f"   addr add dev {self._ns_peer.nsims[0].ifname} {self.nsim_v4_pfx}2/24", ns=self._netns)
        ip(f"-6 addr add dev {self._ns_peer.nsims[0].ifname} {self.nsim_v6_pfx}2/64 nodad", ns=self._netns)
        ip(f"   link set dev {self._ns_peer.nsims[0].ifname} up", ns=self._netns)

    def __enter__(self):
        return self

    def __exit__(self, ex_type, ex_value, ex_tb):
        """
        __exit__ gets called at the end of a "with" block.
        """
        self.__del__()

    def __del__(self):
        if self._ns:
            self._ns.remove()
            self._ns = None
        if self._ns_peer:
            self._ns_peer.remove()
            self._ns_peer = None
        if self._netns:
            del self._netns
            self._netns = None
        if self.remote:
            del self.remote
            self.remote = None