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
16
17
18def netmask_prefix_length(netmask):
19    r"""
20    Return the netmask prefix length.
21
22    Description of argument(s):
23    netmask     Netmask value (e.g. "255.255.0.0", "255.255.255.0",
24                                    "255.252.0.0", etc.).
25    """
26
27    # IP address netmask format: '0.0.0.0/255.255.252.0'
28    return ipaddress.ip_network('0.0.0.0/' + netmask).prefixlen
29
30
31def parse_nping_output(output):
32    r"""
33    Parse the output from the nping command and return as a dictionary.
34
35    Example of output value:
36
37    Starting Nping 0.6.47 ( http://nmap.org/nping ) at 2019-08-07 22:05 IST
38    SENT (0.0181s) TCP Source IP:37577 >
39      Destination IP:80 S ttl=64 id=39113 iplen=40  seq=629782493 win=1480
40    SENT (0.2189s) TCP Source IP:37577 >
41      Destination IP:80 S ttl=64 id=39113 iplen=40  seq=629782493 win=1480
42    RCVD (0.4120s) TCP Destination IP:80 >
43      Source IP:37577 SA ttl=49 id=0 iplen=44  seq=1078301364 win=5840 <mss 1380>
44    Max rtt: 193.010ms | Min rtt: 193.010ms | Avg rtt: 193.010ms
45    Raw packets sent: 2 (80B) | Rcvd: 1 (46B) | Lost: 1 (50.00%)
46    Nping done: 1 IP address pinged in 0.43 seconds
47
48    Example of data returned by this function:
49
50    nping_result:
51      [max_rtt]:                 193.010ms
52      [min_rtt]:                 193.010ms
53      [avg_rtt]:                 193.010ms
54      [raw_packets_sent]:        2 (80B)
55      [rcvd]:                    1 (46B)
56      [lost]:                    1 (50.00%)
57      [percent_lost]:            50.00
58
59    Description of argument(s):
60    output                          The output obtained by running an nping
61                                    command.
62    """
63
64    lines = output.split("\n")
65    # Obtain only the lines of interest.
66    lines = list(filter(lambda x: re.match(r"(Max rtt|Raw packets)", x),
67                        lines))
68
69    key_value_list = []
70    for line in lines:
71        key_value_list += line.split("|")
72    nping_result = vf.key_value_list_to_dict(key_value_list)
73    # Extract percent_lost value from lost field.
74    nping_result['percent_lost'] = \
75        float(nping_result['lost'].split(" ")[-1].strip("()%"))
76    return nping_result
77
78
79openbmc_host = BuiltIn().get_variable_value("${OPENBMC_HOST}")
80
81
82def nping(host=openbmc_host, parse_results=1, **options):
83    r"""
84    Run the nping command and return the results either as a string or as a dictionary.
85
86    Do a 'man nping' for a complete description of the nping utility.
87
88    Note that any valid nping argument may be specified as a function argument.
89
90    Example robot code:
91
92    ${nping_result}=  Nping  delay=${delay}  count=${count}  icmp=${None}  icmp-type=echo
93    Rprint Vars  nping_result
94
95    Resulting output:
96
97    nping_result:
98      [max_rtt]:                                      0.534ms
99      [min_rtt]:                                      0.441ms
100      [avg_rtt]:                                      0.487ms
101      [raw_packets_sent]:                             4 (112B)
102      [rcvd]:                                         2 (92B)
103      [lost]:                                         2 (50.00%)
104      [percent_lost]:                                 50.0
105
106    Description of argument(s):
107    host                            The host name or IP of the target of the
108                                    nping command.
109    parse_results                   1 or True indicates that this function
110                                    should parse the nping results and return
111                                    a dictionary rather than the raw nping
112                                    output.  See the parse_nping_output()
113                                    function for details on the dictionary
114                                    structure.
115    options                         Zero or more options accepted by the nping
116                                    command.  Do a 'man nping' for details.
117    """
118
119    command_string = gc.create_command_string('nping', host, options)
120    rc, output = gc.shell_cmd(command_string, print_output=0, ignore_err=0)
121    if parse_results:
122        return parse_nping_output(output)
123
124    return output
125