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