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