aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python
diff options
context:
space:
mode:
authorJan Gelety <jgelety@cisco.com>2020-08-06 03:34:31 +0200
committerJan Gelety <jgelety@cisco.com>2020-08-07 22:03:19 +0200
commitff1f49d9ba97ddfee3229907e3a344503e072578 (patch)
tree44897453f4cddb795ea8adb4cb05af2d12a6f975 /resources/libraries/python
parent42d1016e92cf2b8ba4e493d878c475de325a447a (diff)
Perf: NAT44 endpoint-dependent mode - udp, part I
- continuation of https://gerrit.fd.io/r/c/csit/+/26898 as there was reached limit of changes (1000) Jira: CSIT-1711 - udp synthetic profiles w/o data packets - udp cps perf tests, phase I (no special "search cps" KW) Part I means that we are using MRR tests to collect traffic data until there is ready new CPS test type with corresponding algorithm. Change-Id: I0d30feb9ecf1d0bff937152656f8eb422f831378 Signed-off-by: Jan Gelety <jgelety@cisco.com>
Diffstat (limited to 'resources/libraries/python')
-rw-r--r--resources/libraries/python/Constants.py6
-rw-r--r--resources/libraries/python/IPUtil.py18
-rw-r--r--resources/libraries/python/NATUtil.py148
-rw-r--r--resources/libraries/python/TrafficGenerator.py77
-rw-r--r--resources/libraries/python/VppConfigGenerator.py13
5 files changed, 212 insertions, 50 deletions
diff --git a/resources/libraries/python/Constants.py b/resources/libraries/python/Constants.py
index 90d60ad4e2..73d8b63a0b 100644
--- a/resources/libraries/python/Constants.py
+++ b/resources/libraries/python/Constants.py
@@ -187,13 +187,17 @@ class Constants:
# TRex install directory
TREX_INSTALL_DIR = u"/opt/trex-core-2.73"
+ # TODO: Find the right way how to use it in trex profiles
+ # TRex pcap files directory
+ TREX_PCAP_DIR = f"{TREX_INSTALL_DIR}/scripts/avl"
+
# TRex limit memory.
TREX_LIMIT_MEMORY = get_int_from_env(u"TREX_LIMIT_MEMORY", 8192)
# TRex number of cores
TREX_CORE_COUNT = get_int_from_env(u"TREX_CORE_COUNT", 7)
- # Trex force start regardles ports state
+ # Trex force start regardless ports state
TREX_SEND_FORCE = get_pessimistic_bool_from_env(u"TREX_SEND_FORCE")
# TRex extra commandline arguments
diff --git a/resources/libraries/python/IPUtil.py b/resources/libraries/python/IPUtil.py
index 946f2f7b72..10a231f9df 100644
--- a/resources/libraries/python/IPUtil.py
+++ b/resources/libraries/python/IPUtil.py
@@ -140,6 +140,24 @@ class IPUtil:
PapiSocketExecutor.run_cli_cmd(node, u"show ip6 fib summary")
@staticmethod
+ def vpp_get_ip_table_summary(node):
+ """Get IPv4 FIB table summary on a VPP node.
+
+ :param node: VPP node.
+ :type node: dict
+ """
+ PapiSocketExecutor.run_cli_cmd(node, u"show ip fib summary")
+
+ @staticmethod
+ 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")
+
+ @staticmethod
def vpp_get_ip_tables_prefix(node, address):
"""Get dump of all IP FIB tables on a VPP node.
diff --git a/resources/libraries/python/NATUtil.py b/resources/libraries/python/NATUtil.py
index 2d5c1c7b76..b43058b23f 100644
--- a/resources/libraries/python/NATUtil.py
+++ b/resources/libraries/python/NATUtil.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2019 Cisco and/or its affiliates.
+# Copyright (c) 2020 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -14,16 +14,17 @@
"""NAT utilities library."""
from pprint import pformat
-from socket import AF_INET, inet_pton
from enum import IntEnum
+from ipaddress import IPv4Address
from robot.api import logger
+from resources.libraries.python.Constants import Constants
from resources.libraries.python.InterfaceUtil import InterfaceUtil
from resources.libraries.python.PapiExecutor import PapiSocketExecutor
-class NATConfigFlags(IntEnum):
+class NatConfigFlags(IntEnum):
"""Common NAT plugin APIs"""
NAT_IS_NONE = 0x00
NAT_IS_TWICE_NAT = 0x01
@@ -36,6 +37,13 @@ class NATConfigFlags(IntEnum):
NAT_IS_EXT_HOST_VALID = 0x80
+class NatAddrPortAllocAlg(IntEnum):
+ """NAT Address and port assignment algorithms."""
+ NAT_ALLOC_ALG_DEFAULT = 0
+ NAT_ALLOC_ALG_MAP_E = 1
+ NAT_ALLOC_ALG_PORT_RANGE = 2
+
+
class NATUtil:
"""This class defines the methods to set NAT."""
@@ -43,41 +51,42 @@ class NATUtil:
pass
@staticmethod
- def set_nat44_interfaces(node, int_in, int_out):
+ def set_nat44_interface(node, interface, flag):
"""Set inside and outside interfaces for NAT44.
:param node: DUT node.
- :param int_in: Inside interface.
- :param int_out: Outside interface.
+ :param interface: Inside interface.
+ :param flag: Interface NAT configuration flag name.
:type node: dict
- :type int_in: str
- :type int_out: str
+ :type interface: str
+ :type flag: 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 " \
+ err_msg = f"Failed to set {flag} interface {interface} for NAT44 " \
f"on host {node[u'host']}"
args_in = dict(
- sw_if_index=int_in_idx,
+ sw_if_index=InterfaceUtil.get_sw_if_index(node, interface),
is_add=1,
- flags=getattr(NATConfigFlags, u"NAT_IS_INSIDE").value
+ flags=getattr(NatConfigFlags, flag).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
- )
+ @staticmethod
+ def set_nat44_interfaces(node, int_in, int_out):
+ """Set inside and outside interfaces for NAT44.
- with PapiSocketExecutor(node) as papi_exec:
- papi_exec.add(cmd, **args_in).get_reply(err_msg)
+ :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
+ """
+ NATUtil.set_nat44_interface(node, int_in, u"NAT_IS_INSIDE")
+ NATUtil.set_nat44_interface(node, int_out, u"NAT_IS_OUTSIDE")
@staticmethod
def set_nat44_deterministic(node, ip_in, subnet_in, ip_out, subnet_out):
@@ -99,9 +108,9 @@ class NATUtil:
f"on host {node[u'host']}"
args_in = dict(
is_add=True,
- in_addr=inet_pton(AF_INET, str(ip_in)),
+ in_addr=IPv4Address(str(ip_in)).packed,
in_plen=int(subnet_in),
- out_addr=inet_pton(AF_INET, str(ip_out)),
+ out_addr=IPv4Address(str(ip_out)).packed,
out_plen=int(subnet_out)
)
@@ -109,26 +118,76 @@ class NATUtil:
papi_exec.add(cmd, **args_in).get_reply(err_msg)
@staticmethod
- def show_nat(node):
- """Show the NAT configuration and data.
+ def set_nat44_address_range(
+ node, start_ip, end_ip, vrf_id=Constants.BITWISE_NON_ZERO,
+ flag=u"NAT_IS_NONE"):
+ """Set NAT44 address range.
+
+ :param node: DUT node.
+ :param start_ip: IP range start.
+ :param end_ip: IP range end.
+ :param vrf_id: VRF index (Optional).
+ :param flag: NAT flag name.
+ :type node: dict
+ :type start_ip: str
+ :type end_ip: str
+ :type vrf_id: int
+ :type flag: str
+ """
+ cmd = u"nat44_add_del_address_range"
+ err_msg = f"Failed to set NAT44 address range on host {node[u'host']}"
+ args_in = dict(
+ is_add=True,
+ first_ip_address=IPv4Address(str(start_ip)).packed,
+ last_ip_address=IPv4Address(str(end_ip)).packed,
+ vrf_id=vrf_id,
+ flags=getattr(NatConfigFlags, flag).value
+ )
+
+ with PapiSocketExecutor(node) as papi_exec:
+ papi_exec.add(cmd, **args_in).get_reply(err_msg)
+
+ @staticmethod
+ def show_nat_config(node):
+ """Show the NAT configuration.
+
+ :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)}")
+
+ @staticmethod
+ def show_nat44_summary(node):
+ """Show NAT44 summary on the specified topology node.
+
+ :param node: Topology node.
+ :type node: dict
+ """
+ PapiSocketExecutor.run_cli_cmd(node, u"show nat44 summary")
+
+ @staticmethod
+ def show_nat_base_data(node):
+ """Show the NAT base 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']}"
+ err_msg = f"Failed to get NAT base data on host {node[u'host']}"
with PapiSocketExecutor(node) as papi_exec:
reply = papi_exec.add(cmd).get_reply(err_msg)
@@ -140,9 +199,32 @@ class NATUtil:
u"nat44_interface_addr_dump",
u"nat44_address_dump",
u"nat44_static_mapping_dump",
- u"nat44_user_dump",
u"nat44_interface_dump",
+ ]
+ PapiSocketExecutor.dump_and_log(node, cmds)
+
+ @staticmethod
+ def show_nat_user_data(node):
+ """Show the NAT user data.
+
+ Used data sources:
+
+ nat44_user_dump
+ nat44_user_session_dump
+
+ :param node: DUT node.
+ :type node: dict
+ """
+ cmd = u"nat_show_config"
+ err_msg = f"Failed to get NAT user data 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"nat44_user_dump",
u"nat44_user_session_dump",
- u"nat_det_map_dump"
]
PapiSocketExecutor.dump_and_log(node, cmds)
diff --git a/resources/libraries/python/TrafficGenerator.py b/resources/libraries/python/TrafficGenerator.py
index 119702c15b..54d0fbd502 100644
--- a/resources/libraries/python/TrafficGenerator.py
+++ b/resources/libraries/python/TrafficGenerator.py
@@ -466,9 +466,9 @@ class TrafficGenerator(AbstractMeasurer):
if subtype == NodeSubTypeTG.TREX:
# Last line from console output
line = stdout.splitlines()[-1]
- results = line.split(",")
- if results[-1] == u" ":
- results.remove(u" ")
+ results = line.split(u",")
+ if results[-1] in (u" ", u""):
+ results.pop(-1)
self._result = dict()
for result in results:
key, value = result.split(u"=", maxsplit=1)
@@ -490,22 +490,48 @@ class TrafficGenerator(AbstractMeasurer):
self._result.get(u"client_active_flows")
self._l7_data[u"client"][u"established_flows"] = \
self._result.get(u"client_established_flows")
+ self._l7_data[u"client"][u"err_rx_throttled"] = \
+ self._result.get(u"client_err_rx_throttled")
+ self._l7_data[u"client"][u"err_c_nf_throttled"] = \
+ self._result.get(u"client_err_nf_throttled")
+ self._l7_data[u"client"][u"err_flow_overflow"] = \
+ self._result.get(u"client_err_flow_overflow")
self._l7_data[u"server"] = dict()
self._l7_data[u"server"][u"active_flows"] = \
self._result.get(u"server_active_flows")
self._l7_data[u"server"][u"established_flows"] = \
self._result.get(u"server_established_flows")
+ self._l7_data[u"server"][u"err_rx_throttled"] = \
+ self._result.get(u"client_err_rx_throttled")
if u"udp" in self.traffic_profile:
self._l7_data[u"client"][u"udp"] = dict()
self._l7_data[u"client"][u"udp"][u"established_flows"] = \
self._result.get(u"client_udp_connects")
self._l7_data[u"client"][u"udp"][u"closed_flows"] = \
self._result.get(u"client_udp_closed")
+ self._l7_data[u"client"][u"udp"][u"tx_bytes"] = \
+ self._result.get(u"client_udp_tx_bytes")
+ self._l7_data[u"client"][u"udp"][u"rx_bytes"] = \
+ self._result.get(u"client_udp_rx_bytes")
+ self._l7_data[u"client"][u"udp"][u"tx_packets"] = \
+ self._result.get(u"client_udp_tx_packets")
+ self._l7_data[u"client"][u"udp"][u"rx_packets"] = \
+ self._result.get(u"client_udp_rx_packets")
+ self._l7_data[u"client"][u"udp"][u"keep_drops"] = \
+ self._result.get(u"client_udp_keep_drops")
self._l7_data[u"server"][u"udp"] = dict()
self._l7_data[u"server"][u"udp"][u"accepted_flows"] = \
self._result.get(u"server_udp_accepts")
self._l7_data[u"server"][u"udp"][u"closed_flows"] = \
self._result.get(u"server_udp_closed")
+ self._l7_data[u"server"][u"udp"][u"tx_bytes"] = \
+ self._result.get(u"server_udp_tx_bytes")
+ self._l7_data[u"server"][u"udp"][u"rx_bytes"] = \
+ self._result.get(u"server_udp_rx_bytes")
+ self._l7_data[u"server"][u"udp"][u"tx_packets"] = \
+ self._result.get(u"server_udp_tx_packets")
+ self._l7_data[u"server"][u"udp"][u"rx_packets"] = \
+ self._result.get(u"server_udp_rx_packets")
elif u"tcp" in self.traffic_profile:
self._l7_data[u"client"][u"tcp"] = dict()
self._l7_data[u"client"][u"tcp"][u"initiated_flows"] = \
@@ -514,6 +540,10 @@ class TrafficGenerator(AbstractMeasurer):
self._result.get(u"client_tcp_connects")
self._l7_data[u"client"][u"tcp"][u"closed_flows"] = \
self._result.get(u"client_tcp_closed")
+ self._l7_data[u"client"][u"tcp"][u"tx_bytes"] = \
+ self._result.get(u"client_tcp_tx_bytes")
+ self._l7_data[u"client"][u"tcp"][u"rx_bytes"] = \
+ self._result.get(u"client_tcp_rx_bytes")
self._l7_data[u"server"][u"tcp"] = dict()
self._l7_data[u"server"][u"tcp"][u"accepted_flows"] = \
self._result.get(u"server_tcp_accepts")
@@ -521,6 +551,10 @@ class TrafficGenerator(AbstractMeasurer):
self._result.get(u"server_tcp_connects")
self._l7_data[u"server"][u"tcp"][u"closed_flows"] = \
self._result.get(u"server_tcp_closed")
+ self._l7_data[u"server"][u"tcp"][u"tx_bytes"] = \
+ self._result.get(u"server_tcp_tx_bytes")
+ self._l7_data[u"server"][u"tcp"][u"rx_bytes"] = \
+ self._result.get(u"server_tcp_rx_bytes")
def trex_astf_stop_remote_exec(self, node):
"""Execute T-Rex ASTF script on remote node over ssh to stop running
@@ -668,6 +702,7 @@ class TrafficGenerator(AbstractMeasurer):
self._loss = None
self._latency = None
xstats = [None, None]
+ self._l7_data = dict()
self._l7_data[u"client"] = dict()
self._l7_data[u"client"][u"active_flows"] = None
self._l7_data[u"client"][u"established_flows"] = None
@@ -849,12 +884,11 @@ class TrafficGenerator(AbstractMeasurer):
"""
subtype = check_subtype(self._node)
if subtype == NodeSubTypeTG.TREX:
- self.set_rate_provider_defaults(
- frame_size, traffic_profile,
- traffic_directions=traffic_directions)
+ if self.traffic_profile != str(traffic_profile):
+ self.traffic_profile = str(traffic_profile)
if u"trex-astf" in self.traffic_profile:
self.trex_astf_start_remote_exec(
- duration, int(rate), frame_size, traffic_profile,
+ duration, int(rate), frame_size, self.traffic_profile,
async_call, latency, warmup_time, traffic_directions,
tx_port, rx_port
)
@@ -862,7 +896,7 @@ class TrafficGenerator(AbstractMeasurer):
elif u"trex-sl" in self.traffic_profile:
unit_rate_str = str(rate) + u"pps"
self.trex_stl_start_remote_exec(
- duration, unit_rate_str, frame_size, traffic_profile,
+ duration, unit_rate_str, frame_size, self.traffic_profile,
async_call, latency, warmup_time, traffic_directions,
tx_port, rx_port
)
@@ -999,8 +1033,12 @@ class TrafficGenerator(AbstractMeasurer):
# TG needs target Tr per stream, but reports aggregate Tx and Dx.
unit_rate_int = transmit_rate / float(self.traffic_directions)
self.send_traffic_on_tg(
- duration, unit_rate_int, self.frame_size, self.traffic_profile,
- warmup_time=self.warmup_time, latency=self.use_latency,
+ duration,
+ unit_rate_int,
+ self.frame_size,
+ self.traffic_profile,
+ warmup_time=self.warmup_time,
+ latency=self.use_latency,
traffic_directions=self.traffic_directions
)
return self.get_measurement_result(duration, transmit_rate)
@@ -1019,7 +1057,7 @@ class OptimizedSearch:
maximum_transmit_rate, packet_loss_ratio=0.005,
final_relative_width=0.005, final_trial_duration=30.0,
initial_trial_duration=1.0, number_of_intermediate_phases=2,
- timeout=720.0, doublings=1, traffic_directions=2):
+ timeout=720.0, doublings=1, traffic_directions=2, latency=False):
"""Setup initialized TG, perform optimized search, return intervals.
:param frame_size: Frame size identifier or value [B].
@@ -1044,6 +1082,8 @@ class OptimizedSearch:
less stable tests might get better overal duration with 2 or more.
:param traffic_directions: Traffic is bi- (2) or uni- (1) directional.
Default: 2
+ :param latency: Whether to measure latency during the trial.
+ Default: False.
:type frame_size: str or int
:type traffic_profile: str
:type minimum_transmit_rate: float
@@ -1056,6 +1096,7 @@ class OptimizedSearch:
:type timeout: float
:type doublings: int
:type traffic_directions: int
+ :type latency: bool
:returns: Structure containing narrowed down NDR and PDR intervals
and their measurements.
:rtype: NdrPdrResult
@@ -1069,7 +1110,11 @@ class OptimizedSearch:
u"resources.libraries.python.TrafficGenerator"
)
tg_instance.set_rate_provider_defaults(
- frame_size, traffic_profile, traffic_directions=traffic_directions)
+ frame_size,
+ traffic_profile,
+ traffic_directions=traffic_directions,
+ latency=latency
+ )
algorithm = MultipleLossRatioSearch(
measurer=tg_instance, final_trial_duration=final_trial_duration,
final_relative_width=final_relative_width,
@@ -1130,8 +1175,12 @@ class OptimizedSearch:
u"resources.libraries.python.TrafficGenerator"
)
tg_instance.set_rate_provider_defaults(
- frame_size, traffic_profile, traffic_directions=traffic_directions,
- negative_loss=False, latency=latency)
+ frame_size,
+ traffic_profile,
+ traffic_directions=traffic_directions,
+ negative_loss=False,
+ latency=latency
+ )
algorithm = PLRsearch(
measurer=tg_instance, trial_duration_per_trial=tdpt,
packet_loss_ratio_target=plr_target,
diff --git a/resources/libraries/python/VppConfigGenerator.py b/resources/libraries/python/VppConfigGenerator.py
index f19294965a..68a4e22e6b 100644
--- a/resources/libraries/python/VppConfigGenerator.py
+++ b/resources/libraries/python/VppConfigGenerator.py
@@ -501,12 +501,21 @@ class VppConfigGenerator:
self.add_config_item(self._nodeconfig, u"", path)
def add_nat(self, value=u"deterministic"):
- """Add NAT configuration.
+ """Add NAT mode configuration.
:param value: NAT mode.
:type value: str
"""
- path = [u"nat"]
+ path = [u"nat", value]
+ self.add_config_item(self._nodeconfig, u"", path)
+
+ def add_nat_max_translations_per_thread(self, value):
+ """Add NAT max. translations per thread number configuration.
+
+ :param value: NAT mode.
+ :type value: str
+ """
+ path = [u"nat", u"max translations per thread"]
self.add_config_item(self._nodeconfig, value, path)
def add_nsim_poll_main_thread(self):