Feat/12236 packet count v4 - #43
Conversation
STL_EXACT was never passed to the TRex client manager (AdHocExactStlProfile always constructed the base manager with mode=STL), so it only served to select a separate profile class in the tests. Replace it with a dedicated --trex-exact-count flag that is decoupled from mode selection: the mode stays STL and the exact packet count is handled inside STL's run(). - Remove STL_EXACT from the TrexMode enum and str_to_trex_mode() - Drop 'stl.exact' from --force-trex-mode / --prefer-trex-mode choices - Add --trex-exact-count (store_true) pytest option
Move the STLTXSingleBurst exact-count logic from the AdHocExactStlProfile subclass into the base STL branch of run(). When --trex-exact-count is set, run() builds STLStream/STLTXSingleBurst streams (pps = --trex-pps * multiplier, total_pkts = --trex-total-packets) instead of the duration-based push_remote loop. For non-STL modes the flag is ignored with a warning. - Delete ad_hoc_exact_stl_profile.py - Store request on the base manager so run() can read pytest options - Simplify all 'STL | STL_EXACT' case branches to 'STL'
Remove the AdHocExactStlProfile branches and always instantiate the normal profile class. The exact packet count is now enabled via the --trex-exact-count flag handled centrally in STL's run(), so the tests no longer need to branch on a separate mode. STL is added to the available modes where it was previously only reachable through STL_EXACT.
- Add -ec | --trex-exact-count flag to pytest_start.sh and pass it through - Reword -pps / -tp help to reference the STL exact-count mode - Update README to describe exact packet count as an STL option enabled by --trex-exact-count instead of a separate stl.exact mode
argparse interprets % as a format character in help strings, so the literal <drop_rate%> in the --binary-search help raised 'unsupported format character' when rendering --help. Escape it as %%.
…eparators - Move merge_pcaps() from trex_client_manager.py to util/trex_util.py so it lives with the other TRex helpers. - Introduce a BaseAdHocTrex parent subclass in trex_client_manager.py that owns the shared ad-hoc __init__ (runtime pcaps + STL mode); AdHocStlProfile now inherits it instead of duplicating the constructor. - Use underscore separators for large numeric literals (200_000, 10_000_000) in conftest.py for readability.
Address PR review feedback for the packet-count feature: - Replace the three separate options (--trex-exact-count, --trex-pps, --trex-total-packets) with a single --trex-stl-burst [PPS] [PACKET_COUNT] option (and -sb in pytest_start.sh). Defaults: 200000 PPS, 10000000 packets. - Stream pcap merging in merge_pcaps() (PcapReader/PcapWriter) so large pcaps are not loaded fully into memory. - Introduce a Pcap NamedTuple in trex_client_manager.py and use per-test unique merged pcap names to avoid overwrites/races. - Fix trex client class imports to go through the 'trex' alias so isinstance() checks in STLClient.add_streams() keep working. - Add ruff pre-commit config and ignore runtime-generated merged pcaps. - Update README and param_template accordingly.
There was a problem hiding this comment.
Pull request overview
This PR enhances the Suricata-Test-Suite TRex integration by improving STL PCAP handling (multi-PCAP merging) and adding an STL exact packet-count (“burst”) mode to make traffic generation more deterministic and easier to control across runs and multiplier-based modes.
Changes:
- Added streaming multi-PCAP merge support and integrated merged-PCAP behavior into STL profile initialization.
- Introduced an STL exact-count mode controlled via
--trex-stl-burst, plus corresponding CLI wiring and docs. - Expanded several test suites to allow selecting STL mode via
--force-trex-mode/--prefer-trex-mode, and refactored ad-hoc STL profiles to share a common base.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| util/trex_util.py | Adds merge_pcaps() helper to interleave multiple PCAPs into a single merged PCAP. |
| assets/trex/traffic_profiles/trex_client_manager.py | Refactors PCAP representation, merges multi-PCAP STL profiles, and implements STL burst mode in run(). |
| assets/trex/traffic_profiles/ad_hoc_stl_trex_profile.py | Switches ad-hoc STL profile to reuse the new shared ad-hoc base class. |
| conftest.py | Adds pytest option --trex-stl-burst and updates binary-search help text. |
| pytest_start.sh | Adds -sb/--trex-stl-burst flag parsing and forwards it to pytest. |
| README.md | Documents multi-PCAP STL merging, STL exact-count mode, and mode forcing/preference options. |
| param_template.py | Adjusts MTU parameter list (removes 2500, leaves 3000). |
| tests/web_50_sites/test_web_50_sites.py | Allows STL as a selectable TRex mode for this test. |
| tests/pcap_replay/test_pcap_replay.py | Uses get_trex_mode to validate forced/preferred modes and passes explicit mode into profile. |
| tests/nfs_smb_simple/test_nfs_smb_simple.py | Allows STL as a selectable TRex mode for this test. |
| tests/https_simple/test_https_simple.py | Allows STL as a selectable TRex mode for this test. |
| tests/http_simple/test_http_simple.py | Allows STL as a selectable TRex mode for this test. |
| tests/http_https_smb_simple/test_http_https_smb_simple.py | Allows STL as a selectable TRex mode for this test. |
| .gitignore | Ignores merged STL PCAPs generated at runtime. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| quotas = [w / total_w for w in weights] | ||
| min_q = min(q for q in quotas if q > 0) | ||
| # zero-weight sources emit nothing; others emit at least 1 packet per round | ||
| per_round = [0 if q <= 0 else max(1, round(q / min_q)) for q in quotas] |
There was a problem hiding this comment.
We are using weights with 10, 100, 1000. Not relevant at this scale.
| if total_pkts <= 0: | ||
| raise ValueError( | ||
| "--trex-stl-burst PACKET_COUNT must be > 0, " | ||
| f"got {total_pkts}" | ||
| ) |
There was a problem hiding this comment.
This is a good point.
There was a problem hiding this comment.
Not sure why --trex-stl-burst is being parsed as floats in the first place.
| if [[ "$2" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then | ||
| trex_stl_burst="$2" | ||
| shift | ||
| if [[ "$2" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then | ||
| trex_stl_burst="$trex_stl_burst $2" |
There was a problem hiding this comment.
Will be made more consistent.
| if target_vlan != 0: | ||
| pcap_path = Path(edit_vlan(str(pcap_path), target_vlan)) | ||
| self.pcaps[i] = (pcap_path.name, pcap[1]) | ||
| self.pcaps[i] = Pcap(pcap_path, pcap.weight) | ||
| pcap_remote_path = self.get_remote_data_path(pcap_path) | ||
| send_to_remote(pcap_path, trex_hostname, pcap_remote_path) |
There was a problem hiding this comment.
It is more uniform and simpler this way. And it is just a one time cost on test start, not on test run.
There was a problem hiding this comment.
If I understand the code correctly, the PCAPs are always merged if there is more than one, so this will always be redundant.
--trex-stl-burst is parsed as floats, but TRex requires an integer packet count. Cast total_pkts to int while keeping pps as a float (since pps is scaled by a float multiplier).
|
found a bug where trex refuses float packet values. |
| help=( | ||
| "In STL mode, send a fixed burst of PACKET_COUNT packets at PPS " | ||
| "instead of replaying for the configured duration. With no " | ||
| "arguments, defaults to 200000 PPS and 10000000 packets. Only " |
There was a problem hiding this comment.
Nitpick, but it should be "200 000" and "10 000 000".
| --remote-host="$suricata_server" --param-file="param.py" \ | ||
| --trex-force-use \ | ||
| $trex_mode_flags \ | ||
| ${trex_stl_burst_set:+--trex-stl-burst $trex_stl_burst} \ |
There was a problem hiding this comment.
I assume this conditionally includes the flag if trex_stl_burst_set is not empty, and if that's the case the extra_args array should be used instead.
| defaults are used (200000 PPS, 10000000 packets): | ||
|
|
||
| | `pytest_start.sh` flag | pytest option | Description | | ||
| |---|---|---| | ||
| | `-sb [<PPS> <COUNT>]` | `--trex-stl-burst [<PPS> <PACKET_COUNT>]` | Send a fixed burst of `PACKET_COUNT` packets at `PPS` in STL mode (defaults: 200000 PPS, 10000000 packets) | | ||
|
|
||
| The packet count stays fixed, but the send rate (`pps`) is scaled by the traffic multiplier | ||
| (`effective_pps = PPS * multiplier`), so exact-count works with both multiplier | ||
| enumeration and binary search. | ||
|
|
||
| Examples: | ||
| ```bash | ||
| # Send 1000 packets at 100 pps using STL exact-count mode | ||
| ./pytest_start.sh -s claret -d http_simple -fm stl -f norules -sb 100 1000 | ||
|
|
||
| # Use the default burst (200000 pps, 10000000 packets) |
There was a problem hiding this comment.
The default values are mentioned 3 times.
This will almost certainly be changed at some point and forgotten about, so I wouldn't mention it anywhere outside of conftest.py.
| total = 0 | ||
| try: | ||
| with PcapWriter(str(out_path), append=False, sync=True) as writer: | ||
| while not all(exhausted): |
There was a problem hiding this comment.
This heuristic means that you can exhaust a short PCAP with a large weight very quickly, which will lead to the PCAP being under-represented relative to its expected weight.
Specifically I expect this to be an issue with Web50Sites, which has a DNS PCAP used this way.
I suggest merging the PCAPs until the result has the desired length and restarting any exhausted streams in the process. Though I would probably cap this at around 100K packets. (Or less, if there aren't any performance issues with TRex)
| # the pcaps can end early, so we loop through them | ||
| start = time() | ||
| elapsed = 0 | ||
| pcap_index = 0 | ||
| while elapsed < self.duration: | ||
| pcap = self.pcaps[pcap_index] | ||
| try: | ||
| client.push_remote( | ||
| pcap_filename=str(self.get_remote_data_path(pcap.path)), | ||
| ports=[0], | ||
| ipg_usec=self.BASE_IPG_USEC / pcap.weight, | ||
| speedup=self.multiplier, | ||
| count=1, | ||
| duration=int(self.duration - elapsed), | ||
| ) | ||
| except TRexError: | ||
| # wait if port was not cleared yet | ||
| sleep(0.05) | ||
| elapsed = time() - start | ||
| continue | ||
| elapsed = time() - start | ||
| continue | ||
| elapsed = time() - start | ||
| pcap_index = (pcap_index + 1) % len(self.pcaps) | ||
| pcap_index = (pcap_index + 1) % len(self.pcaps) |
There was a problem hiding this comment.
This can be simplified now that there is only one PCAP.
| # scale the send rate by the traffic multiplier so that binary | ||
| # search (and multiplier enumeration) can vary the speed; the | ||
| # packet count stays fixed | ||
| multiplier = self.multiplier if self.multiplier is not None else 1.0 |
There was a problem hiding this comment.
This is already guarded on top of the function.
| if target_vlan != 0: | ||
| pcap_path = Path(edit_vlan(str(pcap_path), target_vlan)) | ||
| self.pcaps[i] = (pcap_path.name, pcap[1]) | ||
| self.pcaps[i] = Pcap(pcap_path, pcap.weight) | ||
| pcap_remote_path = self.get_remote_data_path(pcap_path) | ||
| send_to_remote(pcap_path, trex_hostname, pcap_remote_path) |
There was a problem hiding this comment.
If I understand the code correctly, the PCAPs are always merged if there is more than one, so this will always be redundant.
This pull request introduces significant improvements to the TRex STL (Stateless) traffic generator integration, focusing on enhanced multi-PCAP handling and the addition of an exact packet count (burst) mode. The changes improve both the usability and determinism of traffic generation for testing. The most important changes are grouped below.
STL Mode Enhancements
--trex-stl-burstoption. This enables deterministic testing where you need to send precisely N packets. The packet count is fixed, but the send rate is scaled by the traffic multiplier, supporting binary search and enumeration.Codebase Refactoring and Usability
PcapNamedTuple for better type safety and clarity, and updated all STL/ASTF/STF profile logic to use this structure. PCAP upload, merging, and replay logic is now more robust and easier to maintain.BaseAdHocTrexclass: Provides a unified base for ad-hoc STL profiles that receive their PCAPs at runtime, ensuring consistent behavior across test profiles.Documentation and Developer Experience
README.mdhas been expanded to describe multi-PCAP merging, the new STL exact-count mode, and usage examples for both. It also documents the new--force-trex-modeand--prefer-trex-modeoptions for test selection.