1#!/usr/bin/env python
2
3r"""
4Network generic functions.
5
6"""
7
8import gen_print as gp
9import gen_cmd as gc
10import gen_misc as gm
11import var_funcs as vf
12import collections
13import re
14import ipaddress
15import subprocess
16from robot.libraries.BuiltIn import BuiltIn
17import json
18import bmc_ssh_utils as bsu
19
20ip_regex = r"\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}"
21
22
23def get_running_system_ip():
24    r"""
25    Get the IP address of server from which robot code is running.
26    """
27
28    stdout = subprocess.check_output("ifconfig", shell=True)
29    stdout = stdout.decode("utf-8")
30    ip_list = re.findall(ip_regex, stdout)
31
32    return ip_list
33
34
35def netmask_prefix_length(netmask):
36    r"""
37    Return the netmask prefix length.
38
39    Description of argument(s):
40    netmask     Netmask value (e.g. "255.255.0.0", "255.255.255.0",
41                                    "255.252.0.0", etc.).
42    """
43
44    # IP address netmask format: '0.0.0.0/255.255.252.0'
45    return ipaddress.ip_network('0.0.0.0/' + netmask).prefixlen
46
47
48def get_netmask_address(prefix_len):
49    r"""
50    Return the netmask address.
51
52    Description of argument(s):
53    prefix_len     Prefix length value (e.g. "24", "23", "22", etc.).
54    """
55
56    # IP address netmask format: '0.0.0.0/24'
57    return ipaddress.ip_network('0.0.0.0/' + prefix_len).netmask
58
59
60def parse_nping_output(output):
61    r"""
62    Parse the output from the nping command and return as a dictionary.
63
64    Example of output value:
65
66    Starting Nping 0.6.47 ( http://nmap.org/nping ) at 2019-08-07 22:05 IST
67    SENT (0.0181s) TCP Source IP:37577 >
68      Destination IP:80 S ttl=64 id=39113 iplen=40  seq=629782493 win=1480
69    SENT (0.2189s) TCP Source IP:37577 >
70      Destination IP:80 S ttl=64 id=39113 iplen=40  seq=629782493 win=1480
71    RCVD (0.4120s) TCP Destination IP:80 >
72      Source IP:37577 SA ttl=49 id=0 iplen=44  seq=1078301364 win=5840 <mss 1380>
73    Max rtt: 193.010ms | Min rtt: 193.010ms | Avg rtt: 193.010ms
74    Raw packets sent: 2 (80B) | Rcvd: 1 (46B) | Lost: 1 (50.00%)
75    Nping done: 1 IP address pinged in 0.43 seconds
76
77    Example of data returned by this function:
78
79    nping_result:
80      [max_rtt]:                 193.010ms
81      [min_rtt]:                 193.010ms
82      [avg_rtt]:                 193.010ms
83      [raw_packets_sent]:        2 (80B)
84      [rcvd]:                    1 (46B)
85      [lost]:                    1 (50.00%)
86      [percent_lost]:            50.00
87
88    Description of argument(s):
89    output                          The output obtained by running an nping
90                                    command.
91    """
92
93    lines = output.split("\n")
94    # Obtain only the lines of interest.
95    lines = list(filter(lambda x: re.match(r"(Max rtt|Raw packets)", x),
96                        lines))
97
98    key_value_list = []
99    for line in lines:
100        key_value_list += line.split("|")
101    nping_result = vf.key_value_list_to_dict(key_value_list)
102    # Extract percent_lost value from lost field.
103    nping_result['percent_lost'] = \
104        float(nping_result['lost'].split(" ")[-1].strip("()%"))
105    return nping_result
106
107
108openbmc_host = BuiltIn().get_variable_value("${OPENBMC_HOST}")
109
110
111def nping(host=openbmc_host, parse_results=1, **options):
112    r"""
113    Run the nping command and return the results either as a string or as a dictionary.
114
115    Do a 'man nping' for a complete description of the nping utility.
116
117    Note that any valid nping argument may be specified as a function argument.
118
119    Example robot code:
120
121    ${nping_result}=  Nping  delay=${delay}  count=${count}  icmp=${None}  icmp-type=echo
122    Rprint Vars  nping_result
123
124    Resulting output:
125
126    nping_result:
127      [max_rtt]:                                      0.534ms
128      [min_rtt]:                                      0.441ms
129      [avg_rtt]:                                      0.487ms
130      [raw_packets_sent]:                             4 (112B)
131      [rcvd]:                                         2 (92B)
132      [lost]:                                         2 (50.00%)
133      [percent_lost]:                                 50.0
134
135    Description of argument(s):
136    host                            The host name or IP of the target of the
137                                    nping command.
138    parse_results                   1 or True indicates that this function
139                                    should parse the nping results and return
140                                    a dictionary rather than the raw nping
141                                    output.  See the parse_nping_output()
142                                    function for details on the dictionary
143                                    structure.
144    options                         Zero or more options accepted by the nping
145                                    command.  Do a 'man nping' for details.
146    """
147
148    command_string = gc.create_command_string('nping', host, options)
149    rc, output = gc.shell_cmd(command_string, print_output=0, ignore_err=0)
150    if parse_results:
151        return parse_nping_output(output)
152
153    return output
154
155
156def get_channel_config():
157    r"""
158    Get the channel config data and return as a dictionary.
159
160    Example:
161    channel_config = get_channel_config()
162    print_vars(channel_config)
163
164    channel_config:
165      [0]:
166        [name]:                  IPMB
167        [is_valid]:              True
168        [active_sessions]:       0
169        [channel_info]:
170          [medium_type]:         ipmb
171          [protocol_type]:       ipmb-1.0
172          [session_supported]:   session-less
173          [is_ipmi]:             True
174      [1]:
175        [name]:                  eth0
176        [is_valid]:              True
177        [active_sessions]:       0
178        [channel_info]:
179          [medium_type]:         other-lan
180          [protocol_type]:       ipmb-1.0
181          [session_supported]:   multi-session
182          [is_ipmi]:             True
183      [2]:
184        [name]:                  eth1
185        [is_valid]:              True
186        [active_sessions]:       0
187        [channel_info]:
188          [medium_type]:         lan-802.3
189          [protocol_type]:       ipmb-1.0
190          [session_supported]:   multi-session
191          [is_ipmi]:             True
192    (etc.)
193    """
194
195    stdout, stderr, rc = bsu.bmc_execute_command("cat /usr/share/ipmi-providers/channel_config.json")
196    return json.loads(stdout)
197
198
199def get_active_channel_config():
200    r"""
201    Channel configs which medium_type are 'other-lan' or 'lan-802.3' returned by
202     this function.
203    """
204
205    return vf.filter_struct(get_channel_config(), "[('medium_type', 'other-lan|lan-802.3')]", regex=1)
206
207
208def get_channel_access_config(file_name):
209    r"""
210    Get the channel access config data and return as a dictionary.
211
212    Description of argument:
213    file_name     File name for channel access settings (e.g. '/run/ipmi/channel_access_volatile.json',
214                 '/var/lib/ipmi/channel_access_nv.json'.).
215
216    Example:
217
218    channel_access_config =  get_channel_access_config()
219    print_vars(channel_access_config)
220
221    channel_access_config:
222        [1]:
223            [priv_limit]:                                 priv-admin
224            [per_msg_auth_disabled]:                      False
225            [access_mode]:                                always_available
226            [alerting_disabled]:                          False
227            [user_auth_disabled]:                         False
228        [2]:
229            [priv_limit]:                                 priv-admin
230            [per_msg_auth_disabled]:                      False
231            [access_mode]:                                always_available
232            [alerting_disabled]:                          False
233            [user_auth_disabled]:                         False
234    """
235    stdout, stderr, rc = bsu.bmc_execute_command("cat " + file_name)
236
237    return json.loads(stdout)
238