1#!/usr/bin/env python3 2 3r""" 4Network generic functions. 5 6""" 7 8import collections 9import ipaddress 10import json 11import re 12import socket 13import subprocess 14 15import bmc_ssh_utils as bsu 16import gen_cmd as gc 17import gen_misc as gm 18import gen_print as gp 19import var_funcs as vf 20from robot.libraries.BuiltIn import BuiltIn 21 22ip_regex = r"\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}" 23 24 25def get_running_system_ip(): 26 r""" 27 Get the IP address of server from which robot code is running. 28 29 """ 30 31 ip_list = list() 32 stdout = subprocess.check_output(["hostname", "--all-fqdns"], shell=True) 33 host_fqdns = stdout.decode("utf-8").strip() 34 ip_address = socket.gethostbyname(str(host_fqdns)) 35 ip_list.append(ip_address) 36 37 return ip_list 38 39 40def 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' 50 return ipaddress.ip_network("0.0.0.0/" + netmask).prefixlen 51 52 53def 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' 62 return ipaddress.ip_network("0.0.0.0/" + prefix_len).netmask 63 64 65def 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%) 80 TCP connection attempts: 5 | Successful connections: 5 | Failed: 0 (0.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 [tcp_connection_attempts]: 5 94 [successful_connections]: 5 95 [failed]: 0 (0.00%) 96 [percent_failed]: 0.00 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. 105 lines = list( 106 filter( 107 lambda x: re.match(r"(Max rtt|Raw packets|TCP connection)", x), 108 lines, 109 ) 110 ) 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) 116 # Extract percent_lost/percent_failed value from lost/failed field. 117 if "lost" in nping_result: 118 nping_result["percent_lost"] = float( 119 nping_result["lost"].split(" ")[-1].strip("()%") 120 ) 121 else: 122 nping_result["percent_failed"] = float( 123 nping_result["failed"].split(" ")[-1].strip("()%") 124 ) 125 return nping_result 126 127 128openbmc_host = BuiltIn().get_variable_value("${OPENBMC_HOST}") 129 130 131def 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 168 command_string = gc.create_command_string("nping", host, options) 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 174 175 176def 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 215 stdout, stderr, rc = bsu.bmc_execute_command( 216 "cat /usr/share/ipmi-providers/channel_config.json" 217 ) 218 return json.loads(stdout) 219 220 221def 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 227 return vf.filter_struct( 228 get_channel_config(), 229 "[('medium_type', 'other-lan|lan-802.3')]", 230 regex=1, 231 ) 232 233 234def get_channel_access_config(file_name): 235 r""" 236 Get the channel access config data and return as a dictionary. 237 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 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 """ 261 stdout, stderr, rc = bsu.bmc_execute_command("cat " + file_name) 262 263 return json.loads(stdout) 264