-
Notifications
You must be signed in to change notification settings - Fork 179
virtual_network: add case for basic QinQ check test #6574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
virtual_network: add case for basic QinQ check test #6574
Conversation
WalkthroughAdds a new QinQ (VLAN stacking) test to libvirt tests via three new files. A configuration file defines parameters for a bridge-backed QinQ scenario and VM lifecycle controls. A Python test ( Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (12)
libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg (2)
33-35: 4 GiB transfer by default is overkill for CI4096 (MiB) will bloat runtime and storage; ping/tcpdump already validate datapath.
Consider:
- file_size = 4096 + file_size = 64
20-21: Hard‑coded MAC may collideFixed MAC on a host iface can conflict with existing addresses or NIC policies.
Either omit advlan_mac and skip set_mac in code, or generate a locally-administered MAC at runtime.
provider/virtual_network/script/qinq.sh (4)
1-1: Harden the shell scriptEnable strict mode to catch errors early.
-#!/bin/sh +#!/bin/sh +set -euo pipefail
15-18: Cleanup only when both files existIf one exists, it’s left behind.
-if [ -e $file1 ] && [ -e $file2 ] -then - rm -f $file1 $file2 -fi +rm -f "$file1" "$file2"
20-40: Scale of VLAN creation is excessive for a “basic” testCreating 10×1024 subinterfaces inside the guest is heavy and slow; the Python test only uses v1v10 and v2v10_20.
Add optional args to limit creation (e.g., outer VLAN id and one inner id), or set much smaller defaults (vns_pre=1, vns=32) and let stress tests override.
41-49: Message accuracy and robustnessret2 counts 802.1Q subifaces; message says “dot1ad vlans”.
- echo "$ret2 dot1ad vlans created successfully" + echo "$ret2 VLAN subinterfaces created successfully"Also quote vars in tests/echo for safety.
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py (6)
132-139: Prefer exception logging for debugging md5sum issuesPreserve traceback for IndexError.
- except IndexError: - test.log.error("Could not get file md5sum in guest") + except IndexError: + LOG.exception("Could not get file md5sum in guest")
301-307: Over‑permissive loss thresholdAllowing up to 4/10 packets to drop (>=5%) is too lax for a basic connectivity check.
- if package_lost >= 5: + if package_lost != 0: test.fail( - "%s packeage lost when ping guest ip %s " + "%s packet loss when pinging guest ip %s " % (package_lost, L2tag_iface_ip) )
325-330: MTU tweak may be insufficient for QinQ1504 covers single 802.1Q; QinQ typically needs 1508. This path only pings small packets, but future larger frames will fragment/drop.
Consider 1508 (or negotiated jumbo) when QinQ is active:
- session.cmd("ip link set %s mtu 1504" % nic_name) + session.cmd("ip link set %s mtu 1508" % nic_name)Confirm against your target qemu/NIC behavior.
225-236: Setting a fixed MAC on host VLAN iface is riskyMay conflict with existing MACs and surprises switches.
Avoid set_mac unless required by the environment; let kernel auto‑assign, or generate a locally‑administered MAC.
167-170: Large file creation can dominate runtimedd 64–256 MiB is sufficient to validate scp+md5.
Align default file_size with CI limits and make it overrideable via params.
Also applies to: 331-343
190-196: Guest IP assignment robustnessConsider adding “ip link set up” before assigning and validating with “ip addr show”; some guests require explicit up.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg(1 hunks)libvirt/tests/src/virtual_network/qemu/bridge_qinq.py(1 hunks)provider/virtual_network/script/qinq.sh(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py (2)
libvirt/tests/src/serial/serial_functional.py (1)
wait_for_login(235-258)libvirt/tests/src/virtual_network/iface_bridge.py (1)
ping(83-98)
🪛 Ruff (0.13.1)
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
137-137: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
161-161: Use of possibly insecure function; consider using ast.literal_eval
(S307)
168-168: Probable insecure usage of temporary file or directory: "/var/tmp/transferred_file"
(S108)
178-178: Use of possibly insecure function; consider using ast.literal_eval
(S307)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Python 3.9
- GitHub Check: Python 3.8
- GitHub Check: Python 3.11
- GitHub Check: Python 3.12
| tcpdump_cmd = "setsid tcpdump -xxvvleni %s > %s" | ||
| tcpdump_log = "/tmp/tcpdump-%s.log" | ||
| get_tcpdump_log_cmd = "cat ${tcpdump_log}" | ||
| advlan_name = "${private_bridge}-vl${vlan_id}" | ||
| add_advlan_cmd = "ip link add link ${private_bridge} name ${advlan_name} type vlan proto 802.1ad id ${vlan_id}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tcpdump not backgrounded → test may hang
The command lacks “&” (and stderr redirection). With session.sendline(), tcpdump likely occupies the shell and subsequent commands get fed to tcpdump stdin.
Apply:
- tcpdump_cmd = "setsid tcpdump -xxvvleni %s > %s"
+ tcpdump_cmd = "nohup tcpdump -xxvvleni %s > %s 2>&1 &"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| tcpdump_cmd = "setsid tcpdump -xxvvleni %s > %s" | |
| tcpdump_log = "/tmp/tcpdump-%s.log" | |
| get_tcpdump_log_cmd = "cat ${tcpdump_log}" | |
| advlan_name = "${private_bridge}-vl${vlan_id}" | |
| add_advlan_cmd = "ip link add link ${private_bridge} name ${advlan_name} type vlan proto 802.1ad id ${vlan_id}" | |
| tcpdump_cmd = "nohup tcpdump -xxvvleni %s > %s 2>&1 &" | |
| tcpdump_log = "/tmp/tcpdump-%s.log" | |
| get_tcpdump_log_cmd = "cat ${tcpdump_log}" | |
| advlan_name = "${private_bridge}-vl${vlan_id}" | |
| add_advlan_cmd = "ip link add link ${private_bridge} name ${advlan_name} type vlan proto 802.1ad id ${vlan_id}" |
🤖 Prompt for AI Agents
In libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg around lines 15 to 19,
the tcpdump command is run in the foreground which can block the test shell;
update tcpdump_cmd so tcpdump is backgrounded and its stderr is captured — e.g.
append "2>&1 &" (or use nohup/setsid with trailing "&") so the process detaches
and subsequent commands run; ensure the redirected output still points to the
tcpdump_log variable.
| def check_tcpdump_result( | ||
| session, | ||
| iface_name, | ||
| ethertype, | ||
| ethertype2=None, | ||
| vlan_tag=None, | ||
| vlan_tag2=None, | ||
| enable_logging=False, | ||
| ): | ||
| """ | ||
| Check tcpdump result. | ||
|
|
||
| :param session: guest session | ||
| :param iface_name: the tcpdump file of the interface | ||
| :param ethertype: ethertype value need to be matched | ||
| :param ethertype2: ethertype value 2 needed to be matched if not None | ||
| :param vlan_tag: vlan tag value needed to be matched if not None | ||
| :param vlan_tag2: vlan tag value 2 needed to be matched if not None | ||
| :param enable_logging: whether to dump tcpdump results during test | ||
| """ | ||
| get_tcpdump_log_cmd = params["get_tcpdump_log_cmd"] % iface_name | ||
| tcpdump_content = session.cmd_output( | ||
| get_tcpdump_log_cmd, timeout=300, safe=True | ||
| ).strip() | ||
| lines = tcpdump_content.splitlines() | ||
| sum = 0 | ||
| for i in range(len(lines)): | ||
| if enable_logging: | ||
| test.log.info("line %s: %s", i, lines[i]) | ||
| if not ethertype2: | ||
| if "ICMP echo re" in lines[i] and ethertype in lines[i - 1]: | ||
| sum += 1 | ||
| if vlan_tag and vlan_tag not in lines[i - 1]: | ||
| if "too much work for irq" in lines[i - 1]: | ||
| continue | ||
| else: | ||
| test.fail( | ||
| "in %s tcpdump log, there should be vlan " | ||
| "tag %s" % (iface_name, vlan_tag) | ||
| ) | ||
| elif not vlan_tag: | ||
| if "vlan" in lines[i - 1]: | ||
| test.fail( | ||
| "in %s tcpdump log, there should not be " | ||
| "vlan tag" % iface_name | ||
| ) | ||
| else: | ||
| if ( | ||
| "ICMP echo re" in lines[i] | ||
| and ethertype in lines[i - 1] | ||
| and ethertype2 in lines[i - 1] | ||
| ): | ||
| sum += 1 | ||
| if vlan_tag not in lines[i - 1] or vlan_tag2 not in lines[i - 1]: | ||
| if "too much work for irq" in lines[i - 1]: | ||
| continue | ||
| else: | ||
| test.fail( | ||
| "in %s tcpdump log, there should be vlan " | ||
| "tag %s" % (iface_name, vlan_tag) | ||
| ) | ||
| if sum == 0: | ||
| test.fail( | ||
| "in %s tcpdump log, ethertype is not %s" % (iface_name, ethertype) | ||
| ) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tcpdump parsing off‑by‑one; shadowing built‑in sum
Loop starts at 0 but indexes i-1; at i=0 this reads the last line. Also shadows built‑in sum().
- lines = tcpdump_content.splitlines()
- sum = 0
- for i in range(len(lines)):
+ lines = tcpdump_content.splitlines()
+ matches = 0
+ for i in range(1, len(lines)):
if enable_logging:
test.log.info("line %s: %s", i, lines[i])
if not ethertype2:
if "ICMP echo re" in lines[i] and ethertype in lines[i - 1]:
- sum += 1
+ matches += 1
@@
- if sum == 0:
+ if matches == 0:
test.fail(
"in %s tcpdump log, ethertype is not %s" % (iface_name, ethertype)
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def check_tcpdump_result( | |
| session, | |
| iface_name, | |
| ethertype, | |
| ethertype2=None, | |
| vlan_tag=None, | |
| vlan_tag2=None, | |
| enable_logging=False, | |
| ): | |
| """ | |
| Check tcpdump result. | |
| :param session: guest session | |
| :param iface_name: the tcpdump file of the interface | |
| :param ethertype: ethertype value need to be matched | |
| :param ethertype2: ethertype value 2 needed to be matched if not None | |
| :param vlan_tag: vlan tag value needed to be matched if not None | |
| :param vlan_tag2: vlan tag value 2 needed to be matched if not None | |
| :param enable_logging: whether to dump tcpdump results during test | |
| """ | |
| get_tcpdump_log_cmd = params["get_tcpdump_log_cmd"] % iface_name | |
| tcpdump_content = session.cmd_output( | |
| get_tcpdump_log_cmd, timeout=300, safe=True | |
| ).strip() | |
| lines = tcpdump_content.splitlines() | |
| sum = 0 | |
| for i in range(len(lines)): | |
| if enable_logging: | |
| test.log.info("line %s: %s", i, lines[i]) | |
| if not ethertype2: | |
| if "ICMP echo re" in lines[i] and ethertype in lines[i - 1]: | |
| sum += 1 | |
| if vlan_tag and vlan_tag not in lines[i - 1]: | |
| if "too much work for irq" in lines[i - 1]: | |
| continue | |
| else: | |
| test.fail( | |
| "in %s tcpdump log, there should be vlan " | |
| "tag %s" % (iface_name, vlan_tag) | |
| ) | |
| elif not vlan_tag: | |
| if "vlan" in lines[i - 1]: | |
| test.fail( | |
| "in %s tcpdump log, there should not be " | |
| "vlan tag" % iface_name | |
| ) | |
| else: | |
| if ( | |
| "ICMP echo re" in lines[i] | |
| and ethertype in lines[i - 1] | |
| and ethertype2 in lines[i - 1] | |
| ): | |
| sum += 1 | |
| if vlan_tag not in lines[i - 1] or vlan_tag2 not in lines[i - 1]: | |
| if "too much work for irq" in lines[i - 1]: | |
| continue | |
| else: | |
| test.fail( | |
| "in %s tcpdump log, there should be vlan " | |
| "tag %s" % (iface_name, vlan_tag) | |
| ) | |
| if sum == 0: | |
| test.fail( | |
| "in %s tcpdump log, ethertype is not %s" % (iface_name, ethertype) | |
| ) | |
| def check_tcpdump_result( | |
| session, | |
| iface_name, | |
| ethertype, | |
| ethertype2=None, | |
| vlan_tag=None, | |
| vlan_tag2=None, | |
| enable_logging=False, | |
| ): | |
| """ | |
| Check tcpdump result. | |
| :param session: guest session | |
| :param iface_name: the tcpdump file of the interface | |
| :param ethertype: ethertype value need to be matched | |
| :param ethertype2: ethertype value 2 needed to be matched if not None | |
| :param vlan_tag: vlan tag value needed to be matched if not None | |
| :param vlan_tag2: vlan tag value 2 needed to be matched if not None | |
| :param enable_logging: whether to dump tcpdump results during test | |
| """ | |
| get_tcpdump_log_cmd = params["get_tcpdump_log_cmd"] % iface_name | |
| tcpdump_content = session.cmd_output( | |
| get_tcpdump_log_cmd, timeout=300, safe=True | |
| ).strip() | |
| lines = tcpdump_content.splitlines() | |
| matches = 0 | |
| for i in range(1, len(lines)): | |
| if enable_logging: | |
| test.log.info("line %s: %s", i, lines[i]) | |
| if not ethertype2: | |
| if "ICMP echo re" in lines[i] and ethertype in lines[i - 1]: | |
| matches += 1 | |
| if vlan_tag and vlan_tag not in lines[i - 1]: | |
| if "too much work for irq" in lines[i - 1]: | |
| continue | |
| else: | |
| test.fail( | |
| "in %s tcpdump log, there should be vlan " | |
| "tag %s" % (iface_name, vlan_tag) | |
| ) | |
| elif not vlan_tag: | |
| if "vlan" in lines[i - 1]: | |
| test.fail( | |
| "in %s tcpdump log, there should not be " | |
| "vlan tag" % iface_name | |
| ) | |
| else: | |
| if ( | |
| "ICMP echo re" in lines[i] | |
| and ethertype in lines[i - 1] | |
| and ethertype2 in lines[i - 1] | |
| ): | |
| matches += 1 | |
| if vlan_tag not in lines[i - 1] or vlan_tag2 not in lines[i - 1]: | |
| if "too much work for irq" in lines[i - 1]: | |
| continue | |
| else: | |
| test.fail( | |
| "in %s tcpdump log, there should be vlan " | |
| "tag %s" % (iface_name, vlan_tag) | |
| ) | |
| if matches == 0: | |
| test.fail( | |
| "in %s tcpdump log, ethertype is not %s" % (iface_name, ethertype) | |
| ) |
🤖 Prompt for AI Agents
In libvirt/tests/src/virtual_network/qemu/bridge_qinq.py around lines 58 to 123,
the tcpdump parsing loop starts at i=0 but accesses lines[i-1] (causing an
unintended wrap to the last line) and uses the name "sum" which shadows the
built-in; change the loop to start from 1 (e.g., for i in range(1, len(lines)))
or iterate with enumerate and keep track of the previous line explicitly, and
rename the "sum" variable to a non-built-in name like "match_count" (or "count")
throughout; ensure any early-continue/conditions still reference the correct
previous line and update the final check to use the new variable name.
| network_dict = eval(params.get("network_dict")) | ||
| net_dev = network_xml.NetworkXML() | ||
| net_dev.setup_attrs(**network_dict) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid eval on untrusted params
Use ast.literal_eval.
+import ast
@@
- network_dict = eval(params.get("network_dict"))
+ network_dict = ast.literal_eval(params.get("network_dict"))
@@
- iface_dict = eval(params.get("iface_dict"))
+ iface_dict = ast.literal_eval(params.get("iface_dict"))Also applies to: 178-181
🧰 Tools
🪛 Ruff (0.13.1)
161-161: Use of possibly insecure function; consider using ast.literal_eval
(S307)
🤖 Prompt for AI Agents
In libvirt/tests/src/virtual_network/qemu/bridge_qinq.py around lines 161-164
and 178-181, the code calls eval(params.get("network_dict")) on test input which
is unsafe; replace eval with ast.literal_eval to safely parse the string into a
Python literal, add "import ast" at the top if missing, and guard against
None/invalid input by checking params.get("network_dict") is not None and
catching ValueError/SyntaxError to raise a clear error or fallback.
| # Start tcpdump on L1tag interface and first_nic in guest | ||
| test.log.info("Start tcpdump in %s", vm_name) | ||
| L1tag_tcpdump_log = params.get("tcpdump_log") % L1tag_iface | ||
| L1tag_tcpdump_cmd = params.get("tcpdump_cmd") % (L1tag_iface, L1tag_tcpdump_log) | ||
| first_nic_tcpdump_log = params.get("tcpdump_log") % nic_name | ||
| first_nic_tcpdump_cmd = params.get("tcpdump_cmd") % ( | ||
| nic_name, | ||
| first_nic_tcpdump_log, | ||
| ) | ||
| session.sendline(L1tag_tcpdump_cmd) | ||
| time.sleep(2) | ||
| session.sendline(first_nic_tcpdump_cmd) | ||
| time.sleep(5) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tcpdump not backgrounded (paired with cfg); sendline will block the shell
Without “&”, sendline likely leaves the shell busy under tcpdump, making subsequent sendlines unreliable.
After fixing tcpdump_cmd in cfg, keep a short wait and optionally verify the process is running, or append “; echo READY” and wait for prompt.
| session.cmd("rm -rf %s" % guest_path, ignore_all_errors=True) | ||
| virsh.destroy(vm_name) | ||
|
|
||
| # Cleanup network | ||
| virsh.net_destroy(network_name, ignore_status=True) | ||
| virsh.net_undefine(network_name, ignore_status=True) | ||
|
|
||
| # Cleanup host interfaces | ||
| process.run(f"ip link del {advlan_ifname}", ignore_status=True) | ||
| process.run(f"ip link del {qvlan_ifname}", ignore_status=True) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UnboundLocal on cleanup if setup fails early
advlan_ifname/qvlan_ifname are defined in try; finally may raise before restore.
- try:
+ advlan_ifname = None
+ qvlan_ifname = None
+ try:
@@
- process.run(f"ip link del {advlan_ifname}", ignore_status=True)
- process.run(f"ip link del {qvlan_ifname}", ignore_status=True)
+ if advlan_ifname:
+ process.run(f"ip link del {advlan_ifname}", ignore_status=True)
+ if qvlan_ifname:
+ process.run(f"ip link del {qvlan_ifname}", ignore_status=True)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| session.cmd("rm -rf %s" % guest_path, ignore_all_errors=True) | |
| virsh.destroy(vm_name) | |
| # Cleanup network | |
| virsh.net_destroy(network_name, ignore_status=True) | |
| virsh.net_undefine(network_name, ignore_status=True) | |
| # Cleanup host interfaces | |
| process.run(f"ip link del {advlan_ifname}", ignore_status=True) | |
| process.run(f"ip link del {qvlan_ifname}", ignore_status=True) | |
| advlan_ifname = None | |
| qvlan_ifname = None | |
| try: | |
| session.cmd("rm -rf %s" % guest_path, ignore_all_errors=True) | |
| virsh.destroy(vm_name) | |
| # Cleanup network | |
| virsh.net_destroy(network_name, ignore_status=True) | |
| virsh.net_undefine(network_name, ignore_status=True) | |
| # Cleanup host interfaces | |
| if advlan_ifname: | |
| process.run(f"ip link del {advlan_ifname}", ignore_status=True) | |
| if qvlan_ifname: | |
| process.run(f"ip link del {qvlan_ifname}", ignore_status=True) |
🤖 Prompt for AI Agents
In libvirt/tests/src/virtual_network/qemu/bridge_qinq.py around lines 345 to
355, advlan_ifname and qvlan_ifname are created inside a try block and the
finally cleanup unconditionally uses them, which can raise UnboundLocalError if
setup fails early; initialize both variables to None (or empty strings) before
the try and in the finally guard calls to process.run with a truthy check (e.g.
if advlan_ifname: process.run(...)) so cleanup only runs when the names were
actually set.
| if [ -z $iface ] | ||
| then | ||
| echo "please provide a interface, e.g. `basename $0` eth0" | ||
| exit 0 | ||
| else | ||
| echo "you are testing with $iface." | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bad interface check and exit code
Unquoted variable test and exit 0 on error.
-if [ -z $iface ]
+if [ -z "${iface:-}" ]
then
- echo "please provide a interface, e.g. `basename $0` eth0"
- exit 0
+ echo "please provide an interface, e.g. $(basename "$0") eth0"
+ exit 1📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if [ -z $iface ] | |
| then | |
| echo "please provide a interface, e.g. `basename $0` eth0" | |
| exit 0 | |
| else | |
| echo "you are testing with $iface." | |
| fi | |
| if [ -z "${iface:-}" ] | |
| then | |
| echo "please provide an interface, e.g. $(basename "$0") eth0" | |
| exit 1 | |
| else | |
| echo "you are testing with $iface." | |
| fi |
🤖 Prompt for AI Agents
In provider/virtual_network/script/qinq.sh around lines 8 to 14, the script
tests an unquoted variable and exits with status 0 on error; change the test to
quote the variable (use [ -z "$iface" ] or [[ -z "$iface" ]]) to avoid
word-splitting and globbing issues, print a clear usage/error message to stderr
(e.g., echo >&2 or printf to stderr), and return a non-zero exit code on failure
(use exit 1) so calling processes can detect the error.
fb02151 to
b40b1bf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (6)
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py (4)
217-220: Ensure tcpdump processes are backgrounded and running.After fixing
tcpdump_cmdin the config file to include&, verify the processes are running before continuing.Consider adding a verification step after the sleeps:
session.sendline(L1tag_tcpdump_cmd) time.sleep(2) session.sendline(first_nic_tcpdump_cmd) time.sleep(5) # Verify tcpdump processes are running output = session.cmd_output("pgrep -f tcpdump") if not output.strip(): test.error("tcpdump processes failed to start")
77-114: Fix off-by-one error and rename variable shadowing built-in.The loop starts at index 0 but accesses
lines[i - 1], which wraps to the last line wheni=0. The variable namesumshadows Python's built-in.Apply this diff:
lines = tcpdump_content.splitlines() - sum = 0 - for i in range(len(lines)): + match_count = 0 + for i in range(1, len(lines)): if enable_logging: test.log.info("line %s: %s", i, lines[i]) if not ethertype2: if "ICMP echo re" in lines[i] and ethertype in lines[i - 1]: - sum += 1 + match_count += 1 if vlan_tag and vlan_tag not in lines[i - 1]: if "too much work for irq" in lines[i - 1]: continue else: test.fail( "in %s tcpdump log, there should be vlan " "tag %s" % (iface_name, vlan_tag) ) elif not vlan_tag: if "vlan" in lines[i - 1]: test.fail( "in %s tcpdump log, there should not be " "vlan tag" % iface_name ) else: if ( "ICMP echo re" in lines[i] and ethertype in lines[i - 1] and ethertype2 in lines[i - 1] ): - sum += 1 + match_count += 1 if vlan_tag not in lines[i - 1] or vlan_tag2 not in lines[i - 1]: if "too much work for irq" in lines[i - 1]: continue else: test.fail( "in %s tcpdump log, there should be vlan " "tag %s" % (iface_name, vlan_tag) ) - if sum == 0: + if match_count == 0: test.fail( "in %s tcpdump log, ethertype is not %s" % (iface_name, ethertype) ) - test.log.info("tcpdump result check passed for %s - found %d ICMP echo replies with expected ethertype %s%s%s", - iface_name, sum, ethertype, + test.log.info("tcpdump result check passed for %s - found %d ICMP echo replies with expected ethertype %s%s%s", + iface_name, match_count, ethertype, f" and {ethertype2}" if ethertype2 else "", f" with vlan tags {vlan_tag}{vlan_tag2 if vlan_tag2 else ''}" if vlan_tag else "")
154-154: Replace eval() with ast.literal_eval for security.Using
eval()on test parameters is unsafe and can execute arbitrary code.Apply this diff:
+import ast + @@ - iface_dict = eval(params.get("iface_dict")) + iface_dict = ast.literal_eval(params.get("iface_dict"))
340-348: Initialize cleanup variables and guard cleanup calls.Multiple variables used in the
finallyblock may not be defined if setup fails early:session,advlan_ifname, andqvlan_ifname.Apply this diff:
+ session = None + advlan_ifname = None + qvlan_ifname = None try: @@ finally: utils_net.delete_linux_bridge_tmux(bridge_name, host_iface) - session.cmd("rm -rf %s" % guest_path, ignore_all_errors=True) + if session: + session.cmd("rm -rf %s" % guest_path, ignore_all_errors=True) virsh.destroy(vm_name) # Cleanup host interfaces - process.run(f"ip link del {advlan_ifname}", ignore_status=True) - process.run(f"ip link del {qvlan_ifname}", ignore_status=True) + if advlan_ifname: + process.run(f"ip link del {advlan_ifname}", ignore_status=True) + if qvlan_ifname: + process.run(f"ip link del {qvlan_ifname}", ignore_status=True)libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg (1)
15-15: tcpdump must be backgrounded to prevent shell blocking.The command lacks
&and stderr redirection. When used withsession.sendline()in the test (lines 217, 219, 271-275 in bridge_qinq.py), tcpdump will occupy the foreground and subsequent commands will fail.Apply this diff:
- tcpdump_cmd = "setsid tcpdump -xxvvleni %s > %s" + tcpdump_cmd = "nohup tcpdump -xxvvleni %s > %s 2>&1 &"provider/virtual_network/script/qinq.sh (1)
8-11: Quote variables and exit with non-zero status on error.Unquoted
$ifacecan cause word-splitting issues, andexit 0masks the error from calling scripts.Apply this diff:
-if [ -z $iface ] +if [ -z "${iface:-}" ] then - echo "please provide a interface, e.g. `basename $0` eth0" - exit 0 + echo "please provide an interface, e.g. $(basename "$0") eth0" >&2 + exit 1
🧹 Nitpick comments (8)
provider/virtual_network/script/qinq.sh (4)
15-18: Quote variable expansions in file tests.Unquoted variables can cause unexpected behavior if filenames contain spaces or special characters.
Apply this diff:
-if [ -e $file1 ] && [ -e $file2 ] +if [ -e "$file1" ] && [ -e "$file2" ] then - rm -f $file1 $file2 + rm -f "$file1" "$file2"
20-29: Quote variables and reconsider sleep placement.Multiple issues in the outer loop:
- Unquoted variables can cause word-splitting
sleep 2inside the outer loop adds 20 seconds total; if this is for interface stabilization, consider moving it after each VLAN or reducing the durationApply this diff to quote variables:
-for i in `seq $vns_pre` +for i in $(seq "$vns_pre") do - ip link add link $iface name v1v$i type vlan proto $proto id $i + ip link add link "$iface" name "v1v$i" type vlan proto "$proto" id "$i" if [ $? -eq 0 ] then - echo $i>>$file1 + echo "$i" >> "$file1" else - echo "v1v$i is not created" + echo "v1v$i is not created" >&2 fiConsider whether
sleep 2is necessary for each outer VLAN, or if it could be reduced/removed.
30-39: Quote variables in inner loop.Same quoting issues as the outer loop.
Apply this diff:
- for s in `seq $vns` + for s in $(seq "$vns") do - ip link add link v1v$i name v2v$i\_$s type vlan id $s + ip link add link "v1v$i" name "v2v${i}_${s}" type vlan id "$s" if [ $? -eq 0 ] then - echo $i\_$s>>$file2 + echo "${i}_${s}" >> "$file2" else - echo "v2v$i\_$s is not created" + echo "v2v${i}_${s} is not created" >&2 fi
41-43: Avoid useless use of cat and quote variables.The
cat | wc -lpattern is unnecessary;wc -l < fileis more efficient.Apply this diff:
-ret1=`cat $file1 |wc -l` -ret2=`cat $file2 |wc -l` -if [ $ret1 -eq $vns_pre ] && [ $ret2 -eq $((vns_pre*vns)) ] +ret1=$(wc -l < "$file1") +ret2=$(wc -l < "$file2") +if [ "$ret1" -eq "$vns_pre" ] && [ "$ret2" -eq $((vns_pre * vns)) ]libvirt/tests/src/virtual_network/qemu/bridge_qinq.py (4)
177-177: Remove commented-out code.Commented code adds clutter and should be removed. If needed later, it can be retrieved from version control.
Apply this diff:
stop_NM_cmd = params.get("stop_NM_cmd") session.cmd(stop_NM_cmd, ignore_all_errors=True) - #session = vm.wait_for_login(timeout=login_timeout) test.log.info("TEST_STEP1:Copy qinq script to guest")
185-187: Remove commented-out code.These lines appear to be debugging artifacts.
Apply this diff:
remote.copy_files_to(vm_ip, 'scp', username, password, '22', host_qinq_dir, guest_qinq_dir) - - #vm.copy_files_to(host_qinq_dir, guest_qinq_dir) - - # vm.destroy(gracefully=True) nic_name = utils_net.get_linux_ifname(session, mac)
246-250: Document rationale for different packet loss thresholds.L1 VLAN test requires 0% packet loss (line 246) while L2 VLAN test allows up to 5% loss (line 300). If this difference is intentional due to nested VLAN overhead, consider adding a comment explaining the rationale.
132-137: Consider using test.log.exception for better diagnostics.When catching exceptions,
test.log.exception()automatically includes the traceback, which aids debugging.Apply this diff:
try: output = session.cmd_output("md5sum %s" % guest_path, 120).split()[0] guest_result = re.findall(r"\w+", output)[0] except IndexError: - test.log.error("Could not get file md5sum in guest") + test.log.exception("Could not get file md5sum in guest") return False
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg(1 hunks)libvirt/tests/src/virtual_network/qemu/bridge_qinq.py(1 hunks)provider/virtual_network/script/qinq.sh(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-24T08:01:27.899Z
Learnt from: hholoubk
Repo: autotest/tp-libvirt PR: 6579
File: libvirt/tests/src/sriov/vIOMMU/iommu_device_lifecycle.py:95-97
Timestamp: 2025-09-24T08:01:27.899Z
Learning: In the libvirt test framework used in tp-libvirt, VM cleanup including destroying running VMs is handled by the teardown method (test_obj.teardown_iommu_test()) called in the finally block, so explicit VM destroy calls on timeout are not necessary according to the maintainers.
Applied to files:
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
🧬 Code graph analysis (1)
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py (1)
provider/virtual_network/network_base.py (1)
get_vm_ip(25-60)
🪛 Ruff (0.14.2)
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
136-136: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
154-154: Use of possibly insecure function; consider using ast.literal_eval
(S307)
161-161: Probable insecure usage of temporary file or directory: "/var/tmp/transferred_file"
(S108)
b40b1bf to
62d8d29
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (5)
provider/virtual_network/script/qinq.sh (1)
8-14: Make the interface-argument guard safe and fail correctly.The current test leaves
$ifaceunquoted and exits 0 on missing input, so the script silently succeeds when it should abort. Quote the variable, send the usage message to stderr, and return a non-zero status so the caller can detect the error.-if [ -z $iface ] -then - echo "please provide a interface, e.g. `basename $0` eth0" - exit 0 -else - echo "you are testing with $iface." -fi +if [ -z "${iface:-}" ]; then + echo "please provide an interface, e.g. $(basename "$0") eth0" >&2 + exit 1 +else + echo "you are testing with $iface." +filibvirt/tests/src/virtual_network/qemu/bridge_qinq.py (4)
78-121: Fix tcpdump parsing loop off-by-one.Iterating from 0 while reading
lines[i-1]means the first iteration inspects the last line, so we can report false matches or miss expected tags. It also shadows the built-insum(). Start the loop at 1 (or iterate overlines[1:]) and use a non-built-in counter.- lines = tcpdump_content.splitlines() - sum = 0 - for i in range(len(lines)): + lines = tcpdump_content.splitlines() + match_count = 0 + for i in range(1, len(lines)): if enable_logging: test.log.info("line %s: %s", i, lines[i]) if not ethertype2: if "ICMP echo re" in lines[i] and ethertype in lines[i - 1]: - sum += 1 + match_count += 1 @@ else: if ( "ICMP echo re" in lines[i] and ethertype in lines[i - 1] and ethertype2 in lines[i - 1] ): - sum += 1 + match_count += 1 @@ - if sum == 0: + if match_count == 0: test.fail( "in %s tcpdump log, ethertype is not %s" % (iface_name, ethertype) ) - test.log.info("tcpdump result check passed for %s - found %d ICMP echo replies with expected ethertype %s%s%s", - iface_name, sum, ethertype, - f" and {ethertype2}" if ethertype2 else "", - f" with vlan tags {vlan_tag}{vlan_tag2 if vlan_tag2 else ''}" if vlan_tag else "") + test.log.info( + "tcpdump result check passed for %s - found %d ICMP echo replies with expected ethertype %s%s%s", + iface_name, + match_count, + ethertype, + f" and {ethertype2}" if ethertype2 else "", + f" with vlan tags {vlan_tag}{vlan_tag2 if vlan_tag2 else ''}" if vlan_tag else "", + )
213-216: Run tcpdump in the background before issuing follow-up commands.Each
session.sendlinelaunches tcpdump in the foreground, so the shell never returns to accept the next command; later sendlines just get buffered and the setup hangs intermittently. Background the tcpdump processes (or append the&in the command) and wait briefly for them to come up.- session.sendline(L1tag_tcpdump_cmd) + session.sendline(f"{L1tag_tcpdump_cmd} &") time.sleep(2) - session.sendline(first_nic_tcpdump_cmd) + session.sendline(f"{first_nic_tcpdump_cmd} &") @@ - session.sendline(L1tag_tcpdump_cmd) + session.sendline(f"{L1tag_tcpdump_cmd} &") time.sleep(2) - session.sendline(L2tag_tcpdump_cmd) + session.sendline(f"{L2tag_tcpdump_cmd} &") time.sleep(2) - session.sendline(first_nic_tcpdump_cmd) + session.sendline(f"{first_nic_tcpdump_cmd} &")Also applies to: 265-272
164-170: Make cleanup resilient when setup fails early.If an exception is raised before
session,advlan_ifname, orqvlan_ifnameare assigned, thefinallyblock raisesUnboundLocalErrorand leaks host resources. Initialise these names before thetry, guard their use, and letvirsh.destroyignore the “domain not running” case.- try: + session = None + advlan_ifname = None + qvlan_ifname = None + try: @@ - utils_net.delete_linux_bridge_tmux(bridge_name, host_iface) - session.cmd("rm -rf %s" % guest_path, ignore_all_errors=True) - virsh.destroy(vm_name) - - # Cleanup host interfaces - process.run(f"ip link del {advlan_ifname}", ignore_status=True) - process.run(f"ip link del {qvlan_ifname}", ignore_status=True) + utils_net.delete_linux_bridge_tmux(bridge_name, host_iface) + if session: + session.cmd("rm -rf %s" % guest_path, ignore_all_errors=True) + virsh.destroy(vm_name, ignore_status=True) + + # Cleanup host interfaces + if advlan_ifname: + process.run(f"ip link del {advlan_ifname}", ignore_status=True) + if qvlan_ifname: + process.run(f"ip link del {qvlan_ifname}", ignore_status=True)Also applies to: 336-343
154-155: Stop executing params with eval.
eval(params.get("iface_dict"))runs arbitrary code from the test configuration. Useast.literal_eval(and guard against missing/invalid input) instead, and make the same change for any other structured params.-import os +import ast +import os @@ - iface_dict = eval(params.get("iface_dict")) + iface_dict_raw = params.get("iface_dict") + if not iface_dict_raw: + test.cancel("iface_dict parameter is missing") + try: + iface_dict = ast.literal_eval(iface_dict_raw) + except (ValueError, SyntaxError) as exc: + test.fail(f"iface_dict parameter is not a valid literal: {exc}")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg(1 hunks)libvirt/tests/src/virtual_network/qemu/bridge_qinq.py(1 hunks)provider/virtual_network/script/qinq.sh(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-24T08:01:27.899Z
Learnt from: hholoubk
Repo: autotest/tp-libvirt PR: 6579
File: libvirt/tests/src/sriov/vIOMMU/iommu_device_lifecycle.py:95-97
Timestamp: 2025-09-24T08:01:27.899Z
Learning: In the libvirt test framework used in tp-libvirt, VM cleanup including destroying running VMs is handled by the teardown method (test_obj.teardown_iommu_test()) called in the finally block, so explicit VM destroy calls on timeout are not necessary according to the maintainers.
Applied to files:
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
📚 Learning: 2025-11-03T13:30:16.458Z
Learnt from: smitterl
Repo: autotest/tp-libvirt PR: 6531
File: libvirt/tests/src/virtual_network/qemu/pktgen_burst_mode_test.py:64-67
Timestamp: 2025-11-03T13:30:16.458Z
Learning: In tp-libvirt tests, prefer using a list of cleanup lambda functions that are appended when actions requiring cleanup are performed, then executed in a finally block with individual error handling. Example: `cleanup_actions.append(lambda: undo_action())` followed by iterating through the list in reverse order in the finally block.
Applied to files:
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
🧬 Code graph analysis (1)
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py (1)
provider/virtual_network/network_base.py (1)
get_vm_ip(25-60)
🪛 Ruff (0.14.3)
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
136-136: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
154-154: Use of possibly insecure function; consider using ast.literal_eval
(S307)
161-161: Probable insecure usage of temporary file or directory: "/var/tmp/transferred_file"
(S108)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Python 3.11
- GitHub Check: Python 3.8
- GitHub Check: Python 3.9
- GitHub Check: Python 3.12
| if [ -e $file1 ] && [ -e $file2 ] | ||
| then | ||
| rm -f $file1 $file2 | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clear the tracking files every run.
With the current && gate, you only delete the pass files when both exist; if one remains from a previous failure you reuse stale data and may report success. Remove the conditional and let rm -f delete whatever is present each run.
-if [ -e $file1 ] && [ -e $file2 ]
-then
- rm -f $file1 $file2
-fi
+rm -f "$file1" "$file2"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if [ -e $file1 ] && [ -e $file2 ] | |
| then | |
| rm -f $file1 $file2 | |
| fi | |
| rm -f "$file1" "$file2" |
🤖 Prompt for AI Agents
In provider/virtual_network/script/qinq.sh around lines 15 to 18, the script
only removes tracking files when both exist due to the "if [ -e $file1 ] && [ -e
$file2 ]" check, which can leave stale single files and cause false success;
remove the conditional and simply run "rm -f $file1 $file2" unconditionally so
each run clears any present tracking files (use -f to avoid errors if a file is
missing).
62d8d29 to
3749576
Compare
3749576 to
88e2138
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py (1)
232-238: Missing cleanup for created VLAN interfaces.The test creates
advlan_ifname(line 232) andqvlan_ifname(line 288) but the finally block (lines 347-353) doesn't clean them up. If the test fails or times out after creating these interfaces, they'll be left orphaned on the host.Based on learnings, consider adding cleanup actions to a list:
def run(test, params, env): # ... existing code ... cleanup_actions = [] try: # ... existing setup code ... # Line 234: After advlan creation process.run(add_advlan_cmd) cleanup_actions.append(lambda: process.run(f"ip link del {advlan_ifname}", ignore_status=True)) # Line 288: After qvlan creation process.system_output(add_qvlan_cmd) cleanup_actions.append(lambda: process.run(f"ip link del {qvlan_ifname}", ignore_status=True)) # ... rest of test ... finally: # Execute cleanup actions in reverse order for cleanup_action in reversed(cleanup_actions): try: cleanup_action() except Exception as e: test.log.warning(f"Cleanup failed: {e}") # ... existing finally cleanup ...As per coding guidelines.
Also applies to: 288-293
🧹 Nitpick comments (2)
libvirt/tests/deps/linux_qinq/qinq.sh (2)
22-22: Quote the interface variable and remove unnecessary backslashes.The unquoted
$ifaceon line 22 (and line 32's context) risks word-splitting if the interface name contains spaces or special characters. Additionally, the backslash before underscore inv2v$i\_$s(lines 32, 35) is unnecessary and reduces readability—shell variable syntax doesn't require escaping underscores.Apply this diff:
- ip link add link $iface name v1v$i type vlan proto $proto id $i + ip link add link "$iface" name v1v$i type vlan proto $proto id $i- ip link add link v1v$i name v2v$i\_$s type vlan id $s + ip link add link v1v$i name v2v${i}_${s} type vlan id $s- echo $i\_$s>>$file2 + echo ${i}_${s} >> "$file2"Also consider quoting
$file1and$file2consistently throughout.Also applies to: 32-32
41-42: Quote file paths and avoid uselesscat.The unquoted file paths and
cat | wc -lpattern are minor inefficiencies. While/tmp/pass1and/tmp/pass2are unlikely to contain spaces, defensive quoting is safer.Apply this diff:
-ret1=`cat $file1 |wc -l` -ret2=`cat $file2 |wc -l` +ret1=$(wc -l < "$file1") +ret2=$(wc -l < "$file2")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg(1 hunks)libvirt/tests/deps/linux_qinq/qinq.sh(1 hunks)libvirt/tests/src/virtual_network/qemu/bridge_qinq.py(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: hholoubk
Repo: autotest/tp-libvirt PR: 6579
File: libvirt/tests/src/sriov/vIOMMU/iommu_device_lifecycle.py:95-97
Timestamp: 2025-09-24T08:01:27.899Z
Learning: In the libvirt test framework used in tp-libvirt, VM cleanup including destroying running VMs is handled by the teardown method (test_obj.teardown_iommu_test()) called in the finally block, so explicit VM destroy calls on timeout are not necessary according to the maintainers.
📚 Learning: 2025-09-24T08:01:27.899Z
Learnt from: hholoubk
Repo: autotest/tp-libvirt PR: 6579
File: libvirt/tests/src/sriov/vIOMMU/iommu_device_lifecycle.py:95-97
Timestamp: 2025-09-24T08:01:27.899Z
Learning: In the libvirt test framework used in tp-libvirt, VM cleanup including destroying running VMs is handled by the teardown method (test_obj.teardown_iommu_test()) called in the finally block, so explicit VM destroy calls on timeout are not necessary according to the maintainers.
Applied to files:
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
📚 Learning: 2025-11-03T13:30:16.458Z
Learnt from: smitterl
Repo: autotest/tp-libvirt PR: 6531
File: libvirt/tests/src/virtual_network/qemu/pktgen_burst_mode_test.py:64-67
Timestamp: 2025-11-03T13:30:16.458Z
Learning: In tp-libvirt tests, prefer using a list of cleanup lambda functions that are appended when actions requiring cleanup are performed, then executed in a finally block with individual error handling. Example: `cleanup_actions.append(lambda: undo_action())` followed by iterating through the list in reverse order in the finally block.
Applied to files:
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
🪛 Ruff (0.14.4)
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
136-136: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
157-157: Probable insecure usage of temporary file or directory: "/var/tmp/transferred_file"
(S108)
160-160: Use of possibly insecure function; consider using ast.literal_eval
(S307)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Python 3.12
- GitHub Check: Python 3.11
- GitHub Check: Python 3.9
- GitHub Check: Python 3.8
| private_bridge = qinq_br | ||
| func_supported_since_qemu_kvm_ver = (8, 1, 0) | ||
| create_vm_libvirt = "yes" | ||
| image_snapshot = "yes" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicate image_snapshot setting.
The parameter image_snapshot is defined twice with conflicting values ("yes" on line 8, no on line 33). The later assignment on line 33 will override line 8, making line 8 redundant and confusing.
Apply this diff to remove the duplicate:
func_supported_since_qemu_kvm_ver = (8, 1, 0)
create_vm_libvirt = "yes"
- image_snapshot = "yes"
kill_vm_libvirt = "yes"Also applies to: 33-33
🤖 Prompt for AI Agents
In libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg around line 8, remove
the duplicate image_snapshot setting which conflicts with the later definition
(line 33); delete the line containing image_snapshot = "yes" so only the
intended image_snapshot = "no" at line 33 remains, avoiding redundancy and
confusion.
| finally: | ||
| session.cmd("rm -rf %s" % guest_path) | ||
| session.close() | ||
| virsh.destroy(vm_name) | ||
| host_bridge_iface.down() | ||
| host_bridges.del_bridge(brname) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard cleanup actions against uninitialized variables.
The finally block accesses session, host_bridge_iface, and host_bridges without checking if they were successfully initialized. If the test fails early (e.g., session creation fails at line 165 or 191, or bridge creation fails at line 180), the cleanup will raise NameError or AttributeError, masking the original failure.
Apply this diff:
+ session = None
+ host_bridge_iface = None
+ host_bridges = None
+
try:
vm = env.get_vm(params["main_vm"])
# ... rest of try block ...
finally:
- session.cmd("rm -rf %s" % guest_path)
- session.close()
+ if session:
+ try:
+ session.cmd("rm -rf %s" % guest_path, ignore_all_errors=True)
+ session.close()
+ except Exception as e:
+ test.log.warning(f"Session cleanup failed: {e}")
+
virsh.destroy(vm_name)
- host_bridge_iface.down()
- host_bridges.del_bridge(brname)
+
+ if host_bridge_iface:
+ try:
+ host_bridge_iface.down()
+ except Exception as e:
+ test.log.warning(f"Bridge interface cleanup failed: {e}")
+
+ if host_bridges and brname:
+ try:
+ host_bridges.del_bridge(brname)
+ except Exception as e:
+ test.log.warning(f"Bridge deletion failed: {e}")Note: Based on learnings, VM cleanup is handled by the test framework's teardown, so virsh.destroy(vm_name) may be redundant but doesn't hurt.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In libvirt/tests/src/virtual_network/qemu/bridge_qinq.py around lines 347 to
353, the finally block assumes variables session, host_bridge_iface, and
host_bridges are always initialized which can raise NameError/AttributeError and
hide the original failure; update the cleanup to defensively check each resource
before using it (e.g., test for existence or not None via 'if "session" in
locals() and session is not None' or similar checks), wrap individual cleanup
steps in small try/except blocks to log but not raise on cleanup errors, only
call session.close() and session.cmd(...) if session was created, only call
host_bridge_iface.down() and host_bridges.del_bridge(brname) if those objects
exist, and keep virsh.destroy(vm_name) if desired (it's optional since teardown
handles VM cleanup).
xxxx-95976: [virtual network][virual-nic-device] Basic QinQ test - 10x4094 check -- only for linux Signed-off-by: nanli <[email protected]>
88e2138 to
4a80859
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (6)
libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg (2)
8-8: Remove duplicateimage_snapshotsetting.The parameter
image_snapshotis defined twice with conflicting values ("yes" on line 8,noon line 33). The later assignment on line 33 will override line 8, making line 8 redundant and confusing.Apply this diff to remove the duplicate:
func_supported_since_qemu_kvm_ver = (8, 1, 0) create_vm_libvirt = "yes" - image_snapshot = "yes" kill_vm_libvirt = "yes"
20-20: Background tcpdump to prevent shell blocking.The tcpdump command lacks "&" for backgrounding and stderr redirection. When executed via
session.sendline()in the Python test, tcpdump will occupy the shell and subsequent commands may be fed to tcpdump's stdin or hang.Apply this diff:
- tcpdump_cmd = "setsid tcpdump -xxvvleni %s > %s" + tcpdump_cmd = "nohup tcpdump -xxvvleni %s > %s 2>&1 &"libvirt/tests/src/virtual_network/qemu/bridge_qinq.py (4)
76-113: Fix off-by-one error and avoid shadowing built-insum.The loop starts at index 0 but accesses
lines[i - 1], which wraps to the last line wheni=0. Additionally, the variable namesumshadows Python's built-in function.Apply this diff:
lines = tcpdump_content.splitlines() - sum = 0 - for i in range(len(lines)): + match_count = 0 + for i in range(1, len(lines)): if enable_logging: test.log.info("line %s: %s", i, lines[i]) if not ethertype2: if "ICMP echo re" in lines[i] and ethertype in lines[i - 1]: - sum += 1 + match_count += 1 if vlan_tag and vlan_tag not in lines[i - 1]: if "too much work for irq" in lines[i - 1]: continue @@ -102,18 +102,18 @@ and ethertype2 in lines[i - 1] ): - sum += 1 + match_count += 1 if vlan_tag not in lines[i - 1] or vlan_tag2 not in lines[i - 1]: if "too much work for irq" in lines[i - 1]: continue @@ -113,7 +113,7 @@ - if sum == 0: + if match_count == 0: test.fail( "in %s tcpdump log, ethertype is not %s" % (iface_name, ethertype) ) - test.log.info("tcpdump result check passed for %s - found %d ICMP echo replies with expected ethertype %s%s%s", - iface_name, sum, ethertype, + test.log.info("tcpdump result check passed for %s - found %d ICMP echo replies", + iface_name, match_count,
158-158: Replaceeval()withast.literal_eval()for security.Using
eval()on test parameters is unsafe as it can execute arbitrary code. Useast.literal_eval()to safely parse dictionary literals.Apply this diff:
+import ast + @@ - iface_dict = eval(params.get("iface_dict")) + iface_dict = ast.literal_eval(params.get("iface_dict"))
223-226: Tcpdump blocking depends on cfg fix.The
sendline()calls will block the shell if the tcpdump command in the configuration file isn't backgrounded. This issue is paired with the configuration file problem.After fixing
tcpdump_cmdin the configuration file to include backgrounding (append2>&1 &), consider adding a brief wait and optionally verifying the tcpdump process is running.
345-350: Guard cleanup against uninitialized variables.The finally block accesses
session,host_bridge_iface, andhost_bridgeswithout checking if they were successfully initialized. If the test fails early (e.g., before line 163, 172, or 178), cleanup will raiseNameErrorand mask the original failure. Additionally, line 346 redundantly cleans upguest_pathwhich is already done at line 343.Apply this diff:
+ session = None + host_bridge_iface = None + host_bridges = None + try: vm = env.get_vm(params["main_vm"]) @@ finally: - session.cmd("rm -rf %s" % guest_path) - session.close() + if session: + try: + session.close() + except Exception as e: + test.log.warning(f"Session cleanup failed: {e}") + virsh.destroy(vm_name) - host_bridge_iface.down() - host_bridges.del_bridge(brname) + + if host_bridge_iface: + try: + host_bridge_iface.down() + except Exception as e: + test.log.warning(f"Bridge interface cleanup failed: {e}") + + if host_bridges: + try: + host_bridges.del_bridge(brname) + except Exception as e: + test.log.warning(f"Bridge deletion failed: {e}")Based on learnings
🧹 Nitpick comments (1)
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py (1)
230-232: Consider cleaning up VLAN interfaces in finally block.The test creates 802.1ad and 802.1q VLAN interfaces (
advlan_ifnameat line 232 andqvlan_ifnameat line 286) but doesn't explicitly remove them in the finally block. If the test fails partway through, these interfaces may persist on the host.Consider adding VLAN interface cleanup to the finally block:
finally: if session: try: session.close() except Exception as e: test.log.warning(f"Session cleanup failed: {e}") virsh.destroy(vm_name) # Clean up VLAN interfaces if 'advlan_ifname' in locals() and advlan_ifname: try: process.run(f"ip link del {advlan_ifname}", ignore_status=True, shell=True) except Exception as e: test.log.warning(f"Failed to delete {advlan_ifname}: {e}") if 'qvlan_ifname' in locals() and qvlan_ifname: try: process.run(f"ip link del {qvlan_ifname}", ignore_status=True, shell=True) except Exception as e: test.log.warning(f"Failed to delete {qvlan_ifname}: {e}") if host_bridge_iface: try: host_bridge_iface.down() except Exception as e: test.log.warning(f"Bridge interface cleanup failed: {e}") if host_bridges: try: host_bridges.del_bridge(brname) except Exception as e: test.log.warning(f"Bridge deletion failed: {e}")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg(1 hunks)libvirt/tests/deps/linux_qinq/qinq.sh(1 hunks)libvirt/tests/src/virtual_network/qemu/bridge_qinq.py(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- libvirt/tests/deps/linux_qinq/qinq.sh
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-10-24T06:35:25.679Z
Learnt from: meinaLi
Repo: autotest/tp-libvirt PR: 6628
File: libvirt/tests/src/virtual_disks/virtual_disks_io_error.py:128-129
Timestamp: 2025-10-24T06:35:25.679Z
Learning: In libvirt tests, `virsh.snapshot_delete()` without the `--metadata` flag automatically deletes both snapshot metadata and external disk files. Explicit `os.remove()` is only needed when using `virsh.snapshot_delete()` with the `--metadata` flag, which removes only metadata.
Applied to files:
libvirt/tests/cfg/virtual_network/qemu/bridge_qinq.cfg
📚 Learning: 2025-09-24T08:01:27.899Z
Learnt from: hholoubk
Repo: autotest/tp-libvirt PR: 6579
File: libvirt/tests/src/sriov/vIOMMU/iommu_device_lifecycle.py:95-97
Timestamp: 2025-09-24T08:01:27.899Z
Learning: In the libvirt test framework used in tp-libvirt, VM cleanup including destroying running VMs is handled by the teardown method (test_obj.teardown_iommu_test()) called in the finally block, so explicit VM destroy calls on timeout are not necessary according to the maintainers.
Applied to files:
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
📚 Learning: 2025-11-03T13:30:16.458Z
Learnt from: smitterl
Repo: autotest/tp-libvirt PR: 6531
File: libvirt/tests/src/virtual_network/qemu/pktgen_burst_mode_test.py:64-67
Timestamp: 2025-11-03T13:30:16.458Z
Learning: In tp-libvirt tests, prefer using a list of cleanup lambda functions that are appended when actions requiring cleanup are performed, then executed in a finally block with individual error handling. Example: `cleanup_actions.append(lambda: undo_action())` followed by iterating through the list in reverse order in the finally block.
Applied to files:
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
🪛 Ruff (0.14.4)
libvirt/tests/src/virtual_network/qemu/bridge_qinq.py
135-135: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
155-155: Probable insecure usage of temporary file or directory: "/var/tmp/transferred_file"
(S108)
158-158: Use of possibly insecure function; consider using ast.literal_eval
(S307)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Python 3.11
- GitHub Check: Python 3.9
- GitHub Check: Python 3.12
- GitHub Check: Python 3.8
|
@yanglei-rh hi yanglei This pr is updated , and PASSED on kar. I think libvirt-ci and revoke kar and run this test PASS,Please help review it from qemu side , Thanks very much. |
xxxx-95976: [virtual network][virual-nic-device] Basic QinQ test - 10x4094 check -- only for linux
Signed-off-by: nanli [email protected]
hi all reviewers, There is one migrate_from_qemu label set on this patch
This patch is migrated from qemu side, so except the libvirt define xml part , other parts are just copying from qemu side, So Scrum team decide we don't need to review it too detail and focus on libvirt part, Thanks all
Summary by CodeRabbit
Tests
Chores