summaryrefslogtreecommitdiffstats
path: root/nfvbench/traffic_gen/trex_gen.py
diff options
context:
space:
mode:
Diffstat (limited to 'nfvbench/traffic_gen/trex_gen.py')
-rw-r--r--nfvbench/traffic_gen/trex_gen.py81
1 files changed, 75 insertions, 6 deletions
diff --git a/nfvbench/traffic_gen/trex_gen.py b/nfvbench/traffic_gen/trex_gen.py
index d5625eb..41768b1 100644
--- a/nfvbench/traffic_gen/trex_gen.py
+++ b/nfvbench/traffic_gen/trex_gen.py
@@ -26,6 +26,7 @@ from itertools import count
from scapy.contrib.mpls import MPLS # flake8: noqa
# pylint: enable=import-error
from nfvbench.log import LOG
+from nfvbench.specs import ChainType
from nfvbench.traffic_server import TRexTrafficServer
from nfvbench.utils import cast_integer
from nfvbench.utils import timeout
@@ -35,6 +36,7 @@ from hdrh.histogram import HdrHistogram
# pylint: disable=import-error
from trex.common.services.trex_service_arp import ServiceARP
+from trex.stl.api import ARP
from trex.stl.api import bind_layers
from trex.stl.api import CTRexVmInsFixHwCs
from trex.stl.api import Dot1Q
@@ -50,6 +52,7 @@ from trex.stl.api import STLPktBuilder
from trex.stl.api import STLScVmRaw
from trex.stl.api import STLStream
from trex.stl.api import STLTXCont
+from trex.stl.api import STLTXMultiBurst
from trex.stl.api import STLVmFixChecksumHw
from trex.stl.api import STLVmFixIpv4
from trex.stl.api import STLVmFlowVar
@@ -156,6 +159,32 @@ class TRex(AbstractTrafficGenerator):
self.__combine_latencies(in_stats, result[ph]['rx'], ph)
total_tx_pkts = result[0]['tx']['total_pkts'] + result[1]['tx']['total_pkts']
+
+ # in case of GARP packets we need to base total_tx_pkts value using flow_stats
+ # as no GARP packets have no flow stats and will not be received on the other port
+ if self.config.periodic_gratuitous_arp:
+ if not self.config.no_flow_stats and not self.config.no_latency_stats:
+ global_total_tx_pkts = total_tx_pkts
+ total_tx_pkts = 0
+ if ifstats:
+ for chain_id, _ in enumerate(ifstats):
+ for ph in self.port_handle:
+ pg_id, lat_pg_id = self.get_pg_id(ph, chain_id)
+ flows_tx_pkts = in_stats['flow_stats'][pg_id]['tx_pkts']['total'] + \
+ in_stats['flow_stats'][lat_pg_id]['tx_pkts']['total']
+ result[ph]['tx']['total_pkts'] = flows_tx_pkts
+ total_tx_pkts += flows_tx_pkts
+ else:
+ for pg_id in in_stats['flow_stats']:
+ if pg_id != 'global':
+ total_tx_pkts += in_stats['flow_stats'][pg_id]['tx_pkts']['total']
+ result["garp_total_tx_rate"] = cast_integer(
+ (global_total_tx_pkts - total_tx_pkts) / self.config.duration_sec)
+ else:
+ LOG.warning("Gratuitous ARP are not received by the other port so TRex and NFVbench"
+ " see these packets as dropped. Please do not activate no_flow_stats"
+ " and no_latency_stats properties to have a better drop rate.")
+
result["total_tx_rate"] = cast_integer(total_tx_pkts / self.config.duration_sec)
# actual offered tx rate in bps
avg_packet_size = utils.get_average_packet_size(self.l2_frame_size)
@@ -578,6 +607,22 @@ class TRex(AbstractTrafficGenerator):
return STLPktBuilder(pkt=pkt_base / pad,
vm=STLScVmRaw(vm_param, cache_size=int(self.config.cache_size)))
+ def _create_gratuitous_arp_pkt(self, stream_cfg):
+ """Create a GARP packet.
+
+ """
+ pkt_base = Ether(src=stream_cfg['mac_src'], dst="ff:ff:ff:ff:ff:ff")
+
+ if self.config.vxlan or self.config.mpls:
+ pkt_base /= Dot1Q(vlan=stream_cfg['vtep_vlan'])
+ elif stream_cfg['vlan_tag'] is not None:
+ pkt_base /= Dot1Q(vlan=stream_cfg['vlan_tag'])
+
+ pkt_base /= ARP(psrc=stream_cfg['ip_src_tg_gw'], hwsrc=stream_cfg['mac_src'],
+ hwdst=stream_cfg['mac_src'], pdst=stream_cfg['ip_src_tg_gw'])
+
+ return STLPktBuilder(pkt=pkt_base)
+
def generate_streams(self, port, chain_id, stream_cfg, l2frame, latency=True,
e2e=False):
"""Create a list of streams corresponding to a given chain and stream config.
@@ -623,23 +668,31 @@ class TRex(AbstractTrafficGenerator):
else:
l2frame_size = int(l2frame)
pkt = self._create_pkt(stream_cfg, l2frame_size)
+ if self.config.periodic_gratuitous_arp:
+ requested_pps = int(utils.parse_rate_str(self.rates[0])[
+ 'rate_pps']) - self.config.gratuitous_arp_pps
+ if latency:
+ requested_pps -= self.LATENCY_PPS
+ stltx_cont = STLTXCont(pps=requested_pps)
+ else:
+ stltx_cont = STLTXCont()
if e2e or stream_cfg['mpls']:
streams.append(STLStream(packet=pkt,
# Flow stats is disabled for MPLS now
# flow_stats=STLFlowStats(pg_id=pg_id),
- mode=STLTXCont()))
+ mode=stltx_cont))
else:
if stream_cfg['vxlan'] is True:
streams.append(STLStream(packet=pkt,
flow_stats=STLFlowStats(pg_id=pg_id,
vxlan=True)
if not self.config.no_flow_stats else None,
- mode=STLTXCont()))
+ mode=stltx_cont))
else:
streams.append(STLStream(packet=pkt,
flow_stats=STLFlowStats(pg_id=pg_id)
if not self.config.no_flow_stats else None,
- mode=STLTXCont()))
+ mode=stltx_cont))
# for the latency stream, the minimum payload is 16 bytes even in case of vlan tagging
# without vlan, the min l2 frame size is 64
# with vlan it is 68
@@ -669,6 +722,18 @@ class TRex(AbstractTrafficGenerator):
flow_stats=STLFlowLatencyStats(pg_id=lat_pg_id)
if not self.config.no_latency_stats else None,
mode=STLTXCont(pps=self.LATENCY_PPS)))
+
+ if self.config.periodic_gratuitous_arp and (
+ self.config.l3_router or self.config.service_chain == ChainType.EXT):
+ # In case of L3 router feature or EXT chain with router
+ # and depending on ARP stale time SUT configuration
+ # Gratuitous ARP from TG port to the router is needed to keep traffic up
+ garp_pkt = self._create_gratuitous_arp_pkt(stream_cfg)
+ ibg = self.config.gratuitous_arp_pps * 1000000.0
+ packets_count = int(self.config.duration_sec / self.config.gratuitous_arp_pps)
+ streams.append(
+ STLStream(packet=garp_pkt,
+ mode=STLTXMultiBurst(pkts_per_burst=1, count=packets_count, ibg=ibg)))
return streams
@timeout(5)
@@ -986,7 +1051,11 @@ class TRex(AbstractTrafficGenerator):
r = utils.convert_rates(l2frame_size, rates[0], intf_speed)
total_rate = int(r['rate_pps'])
# rate must be enough for latency stream and at least 1 pps for base stream per chain
- required_rate = (self.LATENCY_PPS + 1) * self.config.service_chain_count * mult
+ if self.config.periodic_gratuitous_arp:
+ required_rate = (self.LATENCY_PPS + 1 + self.config.gratuitous_arp_pps) \
+ * self.config.service_chain_count * mult
+ else:
+ required_rate = (self.LATENCY_PPS + 1) * self.config.service_chain_count * mult
result = utils.convert_rates(l2frame_size,
{'rate_pps': required_rate},
intf_speed * mult)
@@ -1059,10 +1128,10 @@ class TRex(AbstractTrafficGenerator):
self.client.reset(self.port_handle)
LOG.info('Cleared all existing streams')
- def get_stats(self, if_stats=None):
+ def get_stats(self, ifstats=None):
"""Get stats from Trex."""
stats = self.client.get_stats()
- return self.extract_stats(stats, if_stats)
+ return self.extract_stats(stats, ifstats)
def get_macs(self):
"""Return the Trex local port MAC addresses.