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