|  | #!/usr/bin/env python3 | 
|  |  | 
|  | r""" | 
|  | Network generic functions. | 
|  |  | 
|  | """ | 
|  |  | 
|  | import collections | 
|  | import ipaddress | 
|  | import json | 
|  | import re | 
|  | import socket | 
|  | import subprocess | 
|  |  | 
|  | import bmc_ssh_utils as bsu | 
|  | import gen_cmd as gc | 
|  | import gen_misc as gm | 
|  | import gen_print as gp | 
|  | import var_funcs as vf | 
|  | from robot.libraries.BuiltIn import BuiltIn | 
|  |  | 
|  | ip_regex = r"\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}" | 
|  |  | 
|  |  | 
|  | def get_running_system_ip(): | 
|  | r""" | 
|  | Get the IP address of server from which robot code is running. | 
|  |  | 
|  | """ | 
|  |  | 
|  | ip_list = list() | 
|  | stdout = subprocess.check_output(["hostname", "--all-fqdns"], shell=True) | 
|  | host_fqdns = stdout.decode("utf-8").strip() | 
|  | ip_address = socket.gethostbyname(str(host_fqdns)) | 
|  | ip_list.append(ip_address) | 
|  |  | 
|  | return ip_list | 
|  |  | 
|  |  | 
|  | def netmask_prefix_length(netmask): | 
|  | r""" | 
|  | Return the netmask prefix length. | 
|  |  | 
|  | Description of argument(s): | 
|  | netmask     Netmask value (e.g. "255.255.0.0", "255.255.255.0", | 
|  | "255.252.0.0", etc.). | 
|  | """ | 
|  |  | 
|  | # IP address netmask format: '0.0.0.0/255.255.252.0' | 
|  | return ipaddress.ip_network("0.0.0.0/" + netmask).prefixlen | 
|  |  | 
|  |  | 
|  | def get_netmask_address(prefix_len): | 
|  | r""" | 
|  | Return the netmask address. | 
|  |  | 
|  | Description of argument(s): | 
|  | prefix_len     Prefix length value (e.g. "24", "23", "22", etc.). | 
|  | """ | 
|  |  | 
|  | # IP address netmask format: '0.0.0.0/24' | 
|  | return ipaddress.ip_network("0.0.0.0/" + prefix_len).netmask | 
|  |  | 
|  |  | 
|  | def parse_nping_output(output): | 
|  | r""" | 
|  | Parse the output from the nping command and return as a dictionary. | 
|  |  | 
|  | Example of output value: | 
|  |  | 
|  | Starting Nping 0.6.47 ( http://nmap.org/nping ) at 2019-08-07 22:05 IST | 
|  | SENT (0.0181s) TCP Source IP:37577 > | 
|  | Destination IP:80 S ttl=64 id=39113 iplen=40  seq=629782493 win=1480 | 
|  | SENT (0.2189s) TCP Source IP:37577 > | 
|  | Destination IP:80 S ttl=64 id=39113 iplen=40  seq=629782493 win=1480 | 
|  | RCVD (0.4120s) TCP Destination IP:80 > | 
|  | Source IP:37577 SA ttl=49 id=0 iplen=44  seq=1078301364 win=5840 <mss 1380> | 
|  | Max rtt: 193.010ms | Min rtt: 193.010ms | Avg rtt: 193.010ms | 
|  | Raw packets sent: 2 (80B) | Rcvd: 1 (46B) | Lost: 1 (50.00%) | 
|  | TCP connection attempts: 5 | Successful connections: 5 | Failed: 0 (0.00%) | 
|  | Nping done: 1 IP address pinged in 0.43 seconds | 
|  |  | 
|  | Example of data returned by this function: | 
|  |  | 
|  | nping_result: | 
|  | [max_rtt]:                 193.010ms | 
|  | [min_rtt]:                 193.010ms | 
|  | [avg_rtt]:                 193.010ms | 
|  | [raw_packets_sent]:        2 (80B) | 
|  | [rcvd]:                    1 (46B) | 
|  | [lost]:                    1 (50.00%) | 
|  | [percent_lost]:            50.00 | 
|  | [tcp_connection_attempts]: 5 | 
|  | [successful_connections]:  5 | 
|  | [failed]:                  0 (0.00%) | 
|  | [percent_failed]:          0.00 | 
|  |  | 
|  | Description of argument(s): | 
|  | output                          The output obtained by running an nping | 
|  | command. | 
|  | """ | 
|  |  | 
|  | lines = output.split("\n") | 
|  | # Obtain only the lines of interest. | 
|  | lines = list( | 
|  | filter( | 
|  | lambda x: re.match(r"(Max rtt|Raw packets|TCP connection)", x), | 
|  | lines, | 
|  | ) | 
|  | ) | 
|  |  | 
|  | key_value_list = [] | 
|  | for line in lines: | 
|  | key_value_list += line.split("|") | 
|  | nping_result = vf.key_value_list_to_dict(key_value_list) | 
|  | # Extract percent_lost/percent_failed value from lost/failed field. | 
|  | if "lost" in nping_result: | 
|  | nping_result["percent_lost"] = float( | 
|  | nping_result["lost"].split(" ")[-1].strip("()%") | 
|  | ) | 
|  | else: | 
|  | nping_result["percent_failed"] = float( | 
|  | nping_result["failed"].split(" ")[-1].strip("()%") | 
|  | ) | 
|  | return nping_result | 
|  |  | 
|  |  | 
|  | openbmc_host = BuiltIn().get_variable_value("${OPENBMC_HOST}") | 
|  |  | 
|  |  | 
|  | def nping(host=openbmc_host, parse_results=1, **options): | 
|  | r""" | 
|  | Run the nping command and return the results either as a string or as a dictionary. | 
|  |  | 
|  | Do a 'man nping' for a complete description of the nping utility. | 
|  |  | 
|  | Note that any valid nping argument may be specified as a function argument. | 
|  |  | 
|  | Example robot code: | 
|  |  | 
|  | ${nping_result}=  Nping  delay=${delay}  count=${count}  icmp=${None}  icmp-type=echo | 
|  | Rprint Vars  nping_result | 
|  |  | 
|  | Resulting output: | 
|  |  | 
|  | nping_result: | 
|  | [max_rtt]:                                      0.534ms | 
|  | [min_rtt]:                                      0.441ms | 
|  | [avg_rtt]:                                      0.487ms | 
|  | [raw_packets_sent]:                             4 (112B) | 
|  | [rcvd]:                                         2 (92B) | 
|  | [lost]:                                         2 (50.00%) | 
|  | [percent_lost]:                                 50.0 | 
|  |  | 
|  | Description of argument(s): | 
|  | host                            The host name or IP of the target of the | 
|  | nping command. | 
|  | parse_results                   1 or True indicates that this function | 
|  | should parse the nping results and return | 
|  | a dictionary rather than the raw nping | 
|  | output.  See the parse_nping_output() | 
|  | function for details on the dictionary | 
|  | structure. | 
|  | options                         Zero or more options accepted by the nping | 
|  | command.  Do a 'man nping' for details. | 
|  | """ | 
|  |  | 
|  | command_string = gc.create_command_string("nping", host, options) | 
|  | rc, output = gc.shell_cmd(command_string, print_output=0, ignore_err=0) | 
|  | if parse_results: | 
|  | return parse_nping_output(output) | 
|  |  | 
|  | return output | 
|  |  | 
|  |  | 
|  | def get_channel_config(): | 
|  | r""" | 
|  | Get the channel config data and return as a dictionary. | 
|  |  | 
|  | Example: | 
|  | channel_config = get_channel_config() | 
|  | print_vars(channel_config) | 
|  |  | 
|  | channel_config: | 
|  | [0]: | 
|  | [name]:                  IPMB | 
|  | [is_valid]:              True | 
|  | [active_sessions]:       0 | 
|  | [channel_info]: | 
|  | [medium_type]:         ipmb | 
|  | [protocol_type]:       ipmb-1.0 | 
|  | [session_supported]:   session-less | 
|  | [is_ipmi]:             True | 
|  | [1]: | 
|  | [name]:                  eth0 | 
|  | [is_valid]:              True | 
|  | [active_sessions]:       0 | 
|  | [channel_info]: | 
|  | [medium_type]:         other-lan | 
|  | [protocol_type]:       ipmb-1.0 | 
|  | [session_supported]:   multi-session | 
|  | [is_ipmi]:             True | 
|  | [2]: | 
|  | [name]:                  eth1 | 
|  | [is_valid]:              True | 
|  | [active_sessions]:       0 | 
|  | [channel_info]: | 
|  | [medium_type]:         lan-802.3 | 
|  | [protocol_type]:       ipmb-1.0 | 
|  | [session_supported]:   multi-session | 
|  | [is_ipmi]:             True | 
|  | (etc.) | 
|  | """ | 
|  |  | 
|  | stdout, stderr, rc = bsu.bmc_execute_command( | 
|  | "cat /usr/share/ipmi-providers/channel_config.json" | 
|  | ) | 
|  | return json.loads(stdout) | 
|  |  | 
|  |  | 
|  | def get_active_channel_config(): | 
|  | r""" | 
|  | Channel configs which medium_type are 'other-lan' or 'lan-802.3' returned by | 
|  | this function. | 
|  | """ | 
|  |  | 
|  | return vf.filter_struct( | 
|  | get_channel_config(), | 
|  | "[('medium_type', 'other-lan|lan-802.3')]", | 
|  | regex=1, | 
|  | ) | 
|  |  | 
|  |  | 
|  | def get_channel_access_config(file_name): | 
|  | r""" | 
|  | Get the channel access config data and return as a dictionary. | 
|  |  | 
|  | Description of argument: | 
|  | file_name     File name for channel access settings (e.g. '/run/ipmi/channel_access_volatile.json', | 
|  | '/var/lib/ipmi/channel_access_nv.json'.). | 
|  |  | 
|  | Example: | 
|  |  | 
|  | channel_access_config =  get_channel_access_config() | 
|  | print_vars(channel_access_config) | 
|  |  | 
|  | channel_access_config: | 
|  | [1]: | 
|  | [priv_limit]:                                 priv-admin | 
|  | [per_msg_auth_disabled]:                      False | 
|  | [access_mode]:                                always_available | 
|  | [alerting_disabled]:                          False | 
|  | [user_auth_disabled]:                         False | 
|  | [2]: | 
|  | [priv_limit]:                                 priv-admin | 
|  | [per_msg_auth_disabled]:                      False | 
|  | [access_mode]:                                always_available | 
|  | [alerting_disabled]:                          False | 
|  | [user_auth_disabled]:                         False | 
|  | """ | 
|  | stdout, stderr, rc = bsu.bmc_execute_command("cat " + file_name) | 
|  |  | 
|  | return json.loads(stdout) |