def vpp_show_errors(node): """Run "show errors" debug CLI command. :param node: Node to run command on. :type node: dict """ PapiSocketExecutor.run_cli_cmd_on_all_sockets(node, u"show errors")
def vpp_get_ip_table(node): """Get IPv4 FIB table on a VPP node. :param node: VPP node. :type node: dict """ PapiSocketExecutor.run_cli_cmd(node, u"show ip fib")
def set_nat44_interfaces(node, int_in, int_out): """Set inside and outside interfaces for NAT44. :param node: DUT node. :param int_in: Inside interface. :param int_out: Outside interface. :type node: dict :type int_in: str :type int_out: str """ cmd = u"nat44_interface_add_del_feature" int_in_idx = InterfaceUtil.get_sw_if_index(node, int_in) err_msg = f"Failed to set inside interface {int_in} for NAT44 " \ f"on host {node[u'host']}" args_in = dict(sw_if_index=int_in_idx, is_add=1, flags=getattr(NATConfigFlags, u"NAT_IS_INSIDE").value) with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args_in).get_reply(err_msg) int_out_idx = InterfaceUtil.get_sw_if_index(node, int_out) err_msg = f"Failed to set outside interface {int_out} for NAT44 " \ f"on host {node[u'host']}" args_in = dict(sw_if_index=int_out_idx, is_add=1, flags=getattr(NATConfigFlags, u"NAT_IS_OUTSIDE").value) with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args_in).get_reply(err_msg)
def show_nat(node): """Show the NAT configuration and data. Used data sources: nat_show_config nat_worker_dump nat44_interface_addr_dump nat44_address_dump nat44_static_mapping_dump nat44_user_dump nat44_interface_dump nat44_user_session_dump nat_det_map_dump :param node: DUT node. :type node: dict """ cmd = u"nat_show_config" err_msg = f"Failed to get NAT configuration on host {node[u'host']}" with PapiSocketExecutor(node) as papi_exec: reply = papi_exec.add(cmd).get_reply(err_msg) logger.debug(f"NAT Configuration:\n{pformat(reply)}") cmds = [ u"nat_worker_dump", u"nat44_interface_addr_dump", u"nat44_address_dump", u"nat44_static_mapping_dump", u"nat44_user_dump", u"nat44_interface_dump", u"nat44_user_session_dump", u"nat_det_map_dump" ] PapiSocketExecutor.dump_and_log(node, cmds)
def show_log(node): """Show logging on the specified topology node. :param node: Topology node. :type node: dict """ PapiSocketExecutor.run_cli_cmd(node, u"show logging")
def set_hoststack_quic_crypto_engine(node, quic_crypto_engine, fail_on_error=False): """Set the Hoststack QUIC crypto engine on node :param node: Node to enable/disable HostStack. :param quic_crypto_engine: type of crypto engine :type node: dict :type quic_crypto_engine: str """ vpp_crypto_engines = {u"openssl", u"native", u"ipsecmb"} if quic_crypto_engine == u"nocrypto": logger.trace(u"No QUIC crypto engine.") return if quic_crypto_engine in vpp_crypto_engines: cmds = [ u"quic set crypto api vpp", f"set crypto handler aes-128-gcm {quic_crypto_engine}", f"set crypto handler aes-256-gcm {quic_crypto_engine}" ] elif quic_crypto_engine == u"picotls": cmds = [u"quic set crypto api picotls"] else: raise ValueError( f"Unknown QUIC crypto_engine {quic_crypto_engine}") for cmd in cmds: try: PapiSocketExecutor.run_cli_cmd(node, cmd) except AssertionError: if fail_on_error: raise
def show_sr_steering_policies(node): """Show SRv6 steering policies on the given node. :param node: Given node to show SRv6 steering policies on. :type node: dict """ cmd = u"sr_steering_pol_dump" PapiSocketExecutor.dump_and_log(node, (cmd, ))
def show_sr_localsids(node): """Show SRv6 LocalSIDs on the given node. :param node: Given node to show localSIDs on. :type node: dict """ cmd = u"sr_localsids_dump" PapiSocketExecutor.dump_and_log(node, (cmd, ))
def vpp_enable_elog_traces(node): """Enable API/CLI/Barrier traces on the specified topology node. :param node: Topology node. :type node: dict """ PapiSocketExecutor.run_cli_cmd_on_all_sockets( node, u"elog trace api cli barrier")
def show_event_logger(node): """Show event logger on the specified topology node. :param node: Topology node. :type node: dict """ PapiSocketExecutor.run_cli_cmd_on_all_sockets(node, u"show event-logger")
def vpp_show_hardware(node): """Run "show hardware" debug CLI command. :param node: Node to run command on. :type node: dict """ PapiSocketExecutor.run_cli_cmd_on_all_sockets( node, u"show hardware verbose")
def vpp_clear_errors(node): """Run "clear errors" CLI command. :param node: Node to run command on. :type node: dict """ PapiSocketExecutor.run_cli_cmd_on_all_sockets(node, u"clear errors", log=False)
def configure_vpp_nsim(node, vpp_nsim_attr, interface0, interface1=None): """Configure nsim on the specified VPP node. :param node: Topology node. :param vpp_nsim_attr: VPP NSIM configuration attributes :param interface0: Interface name. :param interface1: 2nd Interface name for cross-connect feature :type node: dict :type vpp_nsim_attr: dict :type interface0: str or int :type interface1: str or int :raises RuntimeError: if no NSIM features are enabled or vpp papi command fails. """ host = node[u"host"] if not vpp_nsim_attr[u"output_nsim_enable"] \ and not vpp_nsim_attr[u"xc_nsim_enable"]: raise RuntimeError(f"No NSIM features enabled on host {host}:\n" f"vpp_nsim_attr = {vpp_nsim_attr}") cmd = u"nsim_configure2" args = dict(delay_in_usec=vpp_nsim_attr[u"delay_in_usec"], average_packet_size=vpp_nsim_attr[u"average_packet_size"], bandwidth_in_bits_per_second=vpp_nsim_attr[ u"bw_in_bits_per_second"], packets_per_drop=vpp_nsim_attr[u"packets_per_drop"], packets_per_reorder=vpp_nsim_attr.get( u"packets_per_reorder", 0)) err_msg = f"Failed to configure NSIM on host {host}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg) if vpp_nsim_attr[u"output_nsim_enable"]: cmd = u"nsim_output_feature_enable_disable" args = dict( enable_disable=vpp_nsim_attr[u"output_nsim_enable"], sw_if_index=InterfaceUtil.get_interface_index( node, interface0), ) err_msg = f"Failed to enable NSIM output feature on " \ f"host {host} interface {interface0}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg) elif vpp_nsim_attr[u"xc_nsim_enable"]: cmd = u"nsim_cross_connect_feature_enable_disable" args = dict( enable_disable=vpp_nsim_attr[u"xc_nsim_enable"], sw_if_index0=InterfaceUtil.get_interface_index( node, interface0), sw_if_index1=InterfaceUtil.get_interface_index( node, interface1), ) err_msg = f"Failed to enable NSIM output feature on " \ f"host {host} interface {interface0}" with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)
def vpp_show_memory(node): """Run "show memory" debug CLI command. Currently, every flag is hardcoded, giving the longest output. :param node: Node to run command on. :type node: dict """ PapiSocketExecutor.run_cli_cmd_on_all_sockets( node, u"show memory verbose api-segment stats-segment main-heap")
def vpp_log_plugin_acl_interface_assignment(node): """Retrieve interface assignment from the ACL plugin and write to robot log. :param node: VPP node. :type node: dict """ PapiSocketExecutor.dump_and_log(node, [ u"acl_interface_list_dump", ])
def vpp_log_macip_acl_settings(node): """Retrieve configured MACIP settings from the ACL plugin and write to robot log. :param node: VPP node. :type node: dict """ PapiSocketExecutor.dump_and_log(node, [ u"macip_acl_dump", ])
def show_geneve_tunnel_data(node): """Show the GENEVE tunnels data. :param node: DUT node. :type node: dict """ cmds = [ u"geneve_tunnel_dump", ] PapiSocketExecutor.dump_and_log(node, cmds)
def set_hoststack_quic_fifo_size(node, fifo_size): """Set the QUIC protocol fifo size. :param node: Node to set the QUIC fifo size on. :param fifo_size: fifo size, passed to the quic set fifo-size command. :type node: dict :type fifo_size: str """ cmd = f"quic set fifo-size {fifo_size}" PapiSocketExecutor.run_cli_cmd(node, cmd)
def vpp_clear_hardware(node): """Run "clear hardware" CLI command. :param node: Node to run command on. :type node: dict :returns: Verified data from PAPI response. :rtype: dict """ PapiSocketExecutor.run_cli_cmd_on_all_sockets(node, u"clear hardware", log=False)
def start_vpp_http_server_params(cls, node, http_static_plugin, prealloc_fifos, fifo_size, private_segment_size): """Start the test HTTP server internal application or the HTTP static server plugin internal applicatoin on the given node. http static server www-root <www-root-dir> prealloc-fifos <N> fifo-size <size in kB> private-segment-size <seg_size expressed as number + unit, e.g. 100m> -- or -- test http server static prealloc-fifos <N> fifo-size <size in kB> private-segment-size <seg_size expressed as number + unit, e.g. 100m> Where N is the max number of connections you expect to handle at one time and <size> should be small if you test for CPS and exchange few bytes, say 4, if each connection just exchanges few packets. Or it should be much larger, up to 1024/4096 (i.e. 1-4MB) if you have only one connection and exchange a lot of packets, i.e., when you test for RPS. If you need to allocate lots of FIFOs, so you test for CPS, make private-segment-size something like 4g. Example: For CPS http static server www-root <www-root-dir> prealloc-fifos 10000 fifo-size 64 private-segment-size 4000m For RPS test http server static prealloc-fifos 500000 fifo-size 4 private-segment-size 4000m :param node: Node to start HTTP server on. :param http_static_plugin: Run HTTP static server plugin :param prealloc_fifos: Max number of connections you expect to handle at one time. :param fifo_size: FIFO size in kB. :param private_segment_size: Private segment size. Number + unit. :type node: dict :type http_static_plugin: boolean :type prealloc_fifos: str :type fifo_size: str :type private_segment_size: str """ cmd = f"http static server www-root {cls.www_root_dir} " \ f"prealloc-fifos {prealloc_fifos} fifo-size {fifo_size} " \ f"private-segment-size {private_segment_size}" \ if http_static_plugin \ else f"test http server static prealloc-fifos {prealloc_fifos} " \ f"fifo-size {fifo_size} private-segment-size {private_segment_size}" PapiSocketExecutor.run_cli_cmd(node, cmd)
def show_packet_trace_on_all_duts(nodes, maximum=None): """Show VPP packet trace. :param nodes: Nodes from which the packet trace will be displayed. :param maximum: Maximum number of packet traces to be displayed. :type nodes: dict :type maximum: int """ max_opt = f"" if maximum is None else f" max {maximum}" for node in nodes.values(): if node[u"type"] == NodeType.DUT: PapiSocketExecutor.run_cli_cmd_on_all_sockets( node, f"show trace{max_opt}")
def vpp_enable_elog_traces(node): """Enable API/CLI/Barrier traces on the specified topology node. :param node: Topology node. :type node: dict """ try: PapiSocketExecutor.run_cli_cmd_on_all_sockets( node, u"event-logger trace api cli barrier") except AssertionError: # Perhaps an older VPP build is tested. PapiSocketExecutor.run_cli_cmd_on_all_sockets( node, u"elog trace api cli barrier")
def log_vpp_hoststack_data(node): """Retrieve and log VPP HostStack data. :param node: DUT node. :type node: dict :raises RuntimeError: If node subtype is not a DUT or startup failed. """ if node[u"type"] != u"DUT": raise RuntimeError(u"Node type is not a DUT!") PapiSocketExecutor.run_cli_cmd(node, u"show error") PapiSocketExecutor.run_cli_cmd(node, u"show interface")
def vpp_get_ip_tables_prefix(node, address): """Get dump of all IP FIB tables on a VPP node. :param node: VPP node. :param address: IP address. :type node: dict :type address: str """ addr = ip_address(address) ip_ver = u"ip6" if addr.version == 6 else u"ip" PapiSocketExecutor.run_cli_cmd( node, f"show {ip_ver} fib {addr}/{addr.max_prefixlen}")
def _disconnect_papi_to_all_containers(self): """Disconnect any open PAPI connections to VPPs in containers. The current PAPI implementation caches open connections, so explicit disconnect is needed before VPP becomes inaccessible. Currently this is a protected method, as restart, stop and destroy are the only dangerous methods, and all are handled by ContainerManager. """ for container_object in self.containers.values(): PapiSocketExecutor.disconnect_by_node_and_socket( container_object.node, container_object.api_socket, )
def vpp_show_interfaces(node): """Run "show interface" CLI command. :param node: Node to run command on. :type node: dict """ cmd = u"sw_interface_dump" args = dict(name_filter_valid=False, name_filter=u"") err_msg = f"Failed to get interface dump on host {node[u'host']}" with PapiSocketExecutor(node) as papi_exec: details = papi_exec.add(cmd, **args).get_details(err_msg) for if_dump in details: if_dump[u"l2_address"] = str(if_dump[u"l2_address"]) if_dump[u"b_dmac"] = str(if_dump[u"b_dmac"]) if_dump[u"b_smac"] = str(if_dump[u"b_smac"]) if_dump[u"flags"] = if_dump[u"flags"].value if_dump[u"type"] = if_dump[u"type"].value if_dump[u"link_duplex"] = if_dump[u"link_duplex"].value if_dump[u"sub_if_flags"] = if_dump[u"sub_if_flags"].value \ if hasattr(if_dump[u"sub_if_flags"], u"value") \ else int(if_dump[u"sub_if_flags"]) # TODO: return only base data logger.trace(f"Interface data of host {node[u'host']}:\n{details}")
def _memif_create(node, mid, sid, rxq=1, txq=1, role=1): """Create Memif interface on the given node, return its sw_if_index. :param node: Given node to create Memif interface on. :param mid: Memif interface ID. :param sid: Socket ID. :param rxq: Number of RX queues; 0 means do not set. :param txq: Number of TX queues; 0 means do not set. :param role: Memif interface role [master=0|slave=1]. Default is slave. :type node: dict :type mid: str :type sid: str :type rxq: int :type txq: int :type role: int :returns: sw_if_index :rtype: int """ cmd = u"memif_create" err_msg = f"Failed to create memif interface on host {node[u'host']}" args = dict(role=role, rx_queues=int(rxq), tx_queues=int(txq), socket_id=int(sid), id=int(mid), secret=u"") with PapiSocketExecutor(node) as papi_exec: return papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
def gbp_route_domain_add(node, rd_id=1, ip4_table_id=1, ip6_table_id=0, ip4_uu_sw_if_index=0xffffffff, ip6_uu_sw_if_index=0xffffffff): """Add GBP route domain. :param node: Node to add GBP route domain on. :param rd_id: GBP route domain ID. :param ip4_table_id: IPv4 table. :param ip6_table_id: IPv6 table. :param ip4_uu_sw_if_index: IPv4 unicast interface index. :param ip6_uu_sw_if_index: IPv6 unicast interface index. :type node: dict :type rd_id: int :type ip4_table_id: int :type ip6_table_id: int :type ip4_uu_sw_if_index: int :type ip6_uu_sw_if_index: int """ cmd = u"gbp_route_domain_add" err_msg = f"Failed to add GBP route domain on {node[u'host']}!" args_in = dict(rd=dict(rd_id=rd_id, ip4_table_id=ip4_table_id, ip6_table_id=ip6_table_id, ip4_uu_sw_if_index=ip4_uu_sw_if_index, ip6_uu_sw_if_index=ip6_uu_sw_if_index)) with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args_in).get_reply(err_msg)
def vpp_lb_add_del_intf_nat4(node, **kwargs): """Enable/disable NAT4 feature on the interface. :param node: Node where the interface is. :param kwargs: Optional key-value arguments: is_add: true if add, false if delete. (bool) interface: software index of the interface. (int) :type node: dict :type kwargs: dict :returns: Nothing. :raises ValueError: If the node has an unknown node type. """ if node[u"type"] == NodeType.DUT: cmd = u"lb_add_del_intf_nat4" err_msg = f"Failed to add interface nat4 on host {node[u'host']}" is_add = kwargs.pop(u"is_add", True) interface = kwargs.pop(u"interface", 0) sw_if_index = Topology.get_interface_sw_index(node, interface) args = dict(is_add=is_add, sw_if_index=sw_if_index) with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg) else: raise ValueError( f"Node {node[u'host']} has unknown NodeType: '{node[u'type']}'" )
def gbp_ext_itf_add_del(node, sw_if_index, bd_id=1, rd_id=1): """Add external interface to GBP. :param node: Node to add external GBP interface on. :param sw_if_index: SW index of interface. :param bd_id: GBP bridge domain ID. :param rd_id: GBP route domain ID. :type node: dict :type sw_if_index: int :type bd_id: int :type rd_id: int """ cmd = u"gbp_ext_itf_add_del" err_msg = u"Failed to add external GBP interface on {node[u'host']}!" args_in = dict(is_add=True, ext_itf=dict( sw_if_index=sw_if_index, bd_id=bd_id, rd_id=rd_id, flags=getattr(GBPExtItfFlags, u"GBP_API_EXT_ITF_F_NONE").value)) with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args_in).get_reply(err_msg)