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