xref: /freebsd/tests/atf_python/sys/net/tools.py (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1#!/usr/local/bin/python3
2import json
3import os
4
5
6class ToolsHelper(object):
7    NETSTAT_PATH = "/usr/bin/netstat"
8    IFCONFIG_PATH = "/sbin/ifconfig"
9
10    @classmethod
11    def get_output(cls, cmd: str, verbose=False) -> str:
12        if verbose:
13            print("run: '{}'".format(cmd))
14        return os.popen(cmd).read()
15
16    @classmethod
17    def print_output(cls, cmd: str, verbose=True):
18        if verbose:
19            print("======= {} =====".format(cmd))
20        print(cls.get_output(cmd))
21        if verbose:
22            print()
23
24    @classmethod
25    def print_net_debug(cls):
26        cls.print_output("ifconfig")
27        cls.print_output("netstat -rnW")
28
29    @classmethod
30    def set_sysctl(cls, oid, val):
31        cls.get_output("sysctl {}={}".format(oid, val))
32
33    @classmethod
34    def get_routes(cls, family: str, fibnum: int = 0):
35        family_key = {"inet": "-4", "inet6": "-6"}.get(family)
36        out = cls.get_output(
37            "{} {} -rnW -F {} --libxo json".format(cls.NETSTAT_PATH, family_key, fibnum)
38        )
39        js = json.loads(out)
40        js = js["statistics"]["route-information"]["route-table"]["rt-family"]
41        if js:
42            return js[0]["rt-entry"]
43        else:
44            return []
45
46    @classmethod
47    def get_nhops(cls, family: str, fibnum: int = 0):
48        family_key = {"inet": "-4", "inet6": "-6"}.get(family)
49        out = cls.get_output(
50            "{} {} -onW -F {} --libxo json".format(cls.NETSTAT_PATH, family_key, fibnum)
51        )
52        js = json.loads(out)
53        js = js["statistics"]["route-nhop-information"]["nhop-table"]["rt-family"]
54        if js:
55            return js[0]["nh-entry"]
56        else:
57            return []
58
59    @classmethod
60    def get_linklocals(cls):
61        ret = {}
62        ifname = None
63        ips = []
64        for line in cls.get_output(cls.IFCONFIG_PATH).splitlines():
65            if line[0].isalnum():
66                if ifname:
67                    ret[ifname] = ips
68                    ips = []
69                ifname = line.split(":")[0]
70            else:
71                words = line.split()
72                if words[0] == "inet6" and words[1].startswith("fe80"):
73                    # inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
74                    ip = words[1].split("%")[0]
75                    scopeid = int(words[words.index("scopeid") + 1], 16)
76                    ips.append((ip, scopeid))
77        if ifname:
78            ret[ifname] = ips
79        return ret
80