Skip to content

Commit b40b1bf

Browse files
committed
add case for basic QinQ check test
xxxx-95976: [virtual network][virual-nic-device] Basic QinQ test - 10x4094 check -- only for linux Signed-off-by: nanli <[email protected]>
1 parent 1d089a1 commit b40b1bf

File tree

3 files changed

+435
-0
lines changed

3 files changed

+435
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
- virtual_network.qemu_test.bridge_qinq:
2+
only Linux
3+
type = bridge_qinq
4+
private_bridge = qinq_br
5+
func_supported_since_qemu_kvm_ver = (8, 1, 0)
6+
guest_qinq_dir = /home/
7+
qin_script = './../../../../../provider/virtual_network/script/qinq.sh'
8+
ping_count = 10
9+
net_mask = "24"
10+
set_ip_cmd = "ip addr add %s/${net_mask} dev %s"
11+
ip_vm = "192.168.1.2"
12+
vlan_id = 10
13+
L1tag_iface = "v1v${vlan_id}"
14+
L1tag_iface_ip = "192.168.10.10"
15+
tcpdump_cmd = "setsid tcpdump -xxvvleni %s > %s"
16+
tcpdump_log = "/tmp/tcpdump-%s.log"
17+
get_tcpdump_log_cmd = "cat ${tcpdump_log}"
18+
advlan_name = "${private_bridge}-vl${vlan_id}"
19+
add_advlan_cmd = "ip link add link ${private_bridge} name ${advlan_name} type vlan proto 802.1ad id ${vlan_id}"
20+
advlan_mac = "54:52:01:2a:0b:02"
21+
advlan_ip = "192.168.10.1"
22+
L2vid = 20
23+
L2tag_iface = "v2v${vlan_id}_${L2vid}"
24+
L2tag_iface_ip = "192.168.20.10"
25+
qvlan_name = "${private_bridge}-vl${vlan_id}_${L2vid}"
26+
qvlan_ip = "192.168.20.1"
27+
add_qvlan_cmd = "ip link add link ${advlan_name} name ${qvlan_name} type vlan id ${L2vid}"
28+
image_snapshot = no
29+
login_timeout = 720
30+
stop_NM_cmd = "systemctl stop NetworkManager"
31+
firewalld_service = disable
32+
# File transfer test parameters
33+
file_size = 4096
34+
guest_path = "/var/tmp/transferred_file"
35+
transfer_timeout = 1000
36+
shell_port = 22
37+
iface_dict = {'type_name': 'bridge', 'source': {'bridge': '${private_bridge}'}}
Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2+
#
3+
# Copyright Redhat
4+
#
5+
# SPDX-License-Identifier: GPL-2.0
6+
7+
# Author: Nannan Li<[email protected]>
8+
#
9+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10+
import os
11+
import re
12+
import time
13+
14+
from avocado.utils import crypto
15+
from avocado.utils import process
16+
from virttest import utils_misc
17+
18+
from virttest import remote
19+
from virttest import utils_net
20+
from virttest import utils_test
21+
from virttest import virsh
22+
23+
from virttest.libvirt_xml import vm_xml
24+
from virttest.utils_libvirt import libvirt_vmxml
25+
26+
from provider.virtual_network import network_base
27+
28+
29+
def run(test, params, env):
30+
"""
31+
Test basic QinQ - 10 * 4096 with bridge backend using libvirt
32+
33+
1) Create a private bridge using libvirt network
34+
2) Boot a VM over private network
35+
3) Create interfaces in guest with qinq.sh
36+
4) Set IP on guest L1 interface and bring this interface on
37+
5) Create 802.1ad interface on host with the private bridge
38+
6) Start tcpdump on host
39+
7) Do ping test
40+
8) Check tcpdump result with vlan tag and ethertype
41+
9) Set IP on guest L2 interface and bring this interface on
42+
10) Create 802.1q interface on host with the 802.1ad interface
43+
11) Start tcpdump on host
44+
12) Do ping test
45+
13) Check tcpdump result with vlan tag and ethertype
46+
14) SCP file transfer between host and guest
47+
48+
:param test: libvirt test object
49+
:param params: Dictionary with the test parameters
50+
:param env: Dictionary with test environment.
51+
"""
52+
53+
def check_tcpdump_result(
54+
session,
55+
iface_name,
56+
ethertype,
57+
ethertype2=None,
58+
vlan_tag=None,
59+
vlan_tag2=None,
60+
enable_logging=False,
61+
):
62+
"""
63+
Check tcpdump result.
64+
65+
:param session: guest session
66+
:param iface_name: the tcpdump file of the interface
67+
:param ethertype: ethertype value need to be matched
68+
:param ethertype2: ethertype value 2 needed to be matched if not None
69+
:param vlan_tag: vlan tag value needed to be matched if not None
70+
:param vlan_tag2: vlan tag value 2 needed to be matched if not None
71+
:param enable_logging: whether to dump tcpdump results during test
72+
"""
73+
get_tcpdump_log_cmd = params["get_tcpdump_log_cmd"] % iface_name
74+
tcpdump_content = session.cmd_output(
75+
get_tcpdump_log_cmd, timeout=300, safe=True
76+
).strip()
77+
lines = tcpdump_content.splitlines()
78+
sum = 0
79+
for i in range(len(lines)):
80+
if enable_logging:
81+
test.log.info("line %s: %s", i, lines[i])
82+
if not ethertype2:
83+
if "ICMP echo re" in lines[i] and ethertype in lines[i - 1]:
84+
sum += 1
85+
if vlan_tag and vlan_tag not in lines[i - 1]:
86+
if "too much work for irq" in lines[i - 1]:
87+
continue
88+
else:
89+
test.fail(
90+
"in %s tcpdump log, there should be vlan "
91+
"tag %s" % (iface_name, vlan_tag)
92+
)
93+
elif not vlan_tag:
94+
if "vlan" in lines[i - 1]:
95+
test.fail(
96+
"in %s tcpdump log, there should not be "
97+
"vlan tag" % iface_name
98+
)
99+
else:
100+
if (
101+
"ICMP echo re" in lines[i]
102+
and ethertype in lines[i - 1]
103+
and ethertype2 in lines[i - 1]
104+
):
105+
sum += 1
106+
if vlan_tag not in lines[i - 1] or vlan_tag2 not in lines[i - 1]:
107+
if "too much work for irq" in lines[i - 1]:
108+
continue
109+
else:
110+
test.fail(
111+
"in %s tcpdump log, there should be vlan "
112+
"tag %s" % (iface_name, vlan_tag)
113+
)
114+
if sum == 0:
115+
test.fail(
116+
"in %s tcpdump log, ethertype is not %s" % (iface_name, ethertype)
117+
)
118+
test.log.info("tcpdump result check passed for %s - found %d ICMP echo replies with expected ethertype %s%s%s",
119+
iface_name, sum, ethertype,
120+
f" and {ethertype2}" if ethertype2 else "",
121+
f" with vlan tags {vlan_tag}{vlan_tag2 if vlan_tag2 else ''}" if vlan_tag else "")
122+
123+
def compare_host_guest_md5sum():
124+
"""
125+
Compare md5 value of file on host and guest
126+
127+
:param name: file name
128+
129+
"""
130+
test.log.info("Comparing md5sum on guest and host")
131+
host_result = crypto.hash_file(host_path, algorithm="md5")
132+
try:
133+
output = session.cmd_output("md5sum %s" % guest_path, 120).split()[0]
134+
guest_result = re.findall(r"\w+", output)[0]
135+
except IndexError:
136+
test.log.error("Could not get file md5sum in guest")
137+
return False
138+
test.log.debug("md5sum: guest(%s), host(%s)", guest_result, host_result)
139+
return guest_result == host_result
140+
141+
vm_name = params.get('main_vm')
142+
vm = env.get_vm(vm_name)
143+
vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
144+
bk_xml = vmxml.copy()
145+
146+
login_timeout = int(params.get("login_timeout", "600"))
147+
username = params["username"]
148+
password = params["password"]
149+
150+
bridge_name = params.get("private_bridge", "tmpbr")
151+
host_iface = params.get('host_iface')
152+
host_iface = host_iface if host_iface else utils_net.get_default_gateway(
153+
iface_name=True, force_dhcp=True, json=True)
154+
iface_dict = eval(params.get("iface_dict"))
155+
qin_script = params.get('qin_script')
156+
guest_qinq_dir = params["guest_qinq_dir"]
157+
158+
set_ip_cmd = params["set_ip_cmd"]
159+
file_size = int(params.get("file_size", "4096"))
160+
host_path = os.path.join(test.tmpdir, "transferred_file")
161+
guest_path = params.get("guest_path", "/var/tmp/transferred_file")
162+
transfer_timeout = int(params.get("transfer_timeout", 1000))
163+
164+
try:
165+
test.log.info("STEP_UP: Prepare vm with interface")
166+
utils_net.create_linux_bridge_tmux(bridge_name, host_iface)
167+
mac = vmxml.get_first_mac_by_name(vm_name)
168+
iface_dict['mac_address'] = mac
169+
vmxml.del_device('interface', by_tag=True)
170+
libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_dict)
171+
test.log.debug("Guest xml:\n %s", vm_xml.VMXML.new_from_inactive_dumpxml(vm_name))
172+
173+
vm.start()
174+
session = vm.wait_for_serial_login(timeout=login_timeout)
175+
stop_NM_cmd = params.get("stop_NM_cmd")
176+
session.cmd(stop_NM_cmd, ignore_all_errors=True)
177+
#session = vm.wait_for_login(timeout=login_timeout)
178+
test.log.info("TEST_STEP1:Copy qinq script to guest")
179+
host_qinq_dir = os.path.join(os.path.dirname(__file__), qin_script)
180+
vm_ip = network_base.get_vm_ip(session, mac)
181+
182+
remote.copy_files_to(vm_ip, 'scp', username, password,
183+
'22', host_qinq_dir, guest_qinq_dir)
184+
185+
#vm.copy_files_to(host_qinq_dir, guest_qinq_dir)
186+
187+
# vm.destroy(gracefully=True)
188+
nic_name = utils_net.get_linux_ifname(session, mac)
189+
190+
# Set first_nic IP in guest
191+
ip = params["ip_vm"]
192+
session.cmd_output(set_ip_cmd % (ip, nic_name))
193+
194+
# Create vlans via script qinq.sh
195+
output = session.cmd_output(
196+
"sh %sqinq.sh %s" % (guest_qinq_dir, nic_name), timeout=300
197+
)
198+
test.log.info("%s", output)
199+
200+
# Set interface v1v10 IP in guest
201+
L1tag_iface = params["L1tag_iface"]
202+
L1tag_iface_ip = params["L1tag_iface_ip"]
203+
session.cmd_output(set_ip_cmd % (L1tag_iface_ip, L1tag_iface))
204+
session.cmd("ip link set %s up" % L1tag_iface)
205+
output = session.cmd_output("ip addr show %s" % L1tag_iface, timeout=120)
206+
test.log.info(output)
207+
208+
# Start tcpdump on L1tag interface and first_nic in guest
209+
test.log.info("Start tcpdump in %s", vm_name)
210+
L1tag_tcpdump_log = params.get("tcpdump_log") % L1tag_iface
211+
L1tag_tcpdump_cmd = params.get("tcpdump_cmd") % (L1tag_iface, L1tag_tcpdump_log)
212+
first_nic_tcpdump_log = params.get("tcpdump_log") % nic_name
213+
first_nic_tcpdump_cmd = params.get("tcpdump_cmd") % (
214+
nic_name,
215+
first_nic_tcpdump_log,
216+
)
217+
session.sendline(L1tag_tcpdump_cmd)
218+
time.sleep(2)
219+
session.sendline(first_nic_tcpdump_cmd)
220+
time.sleep(5)
221+
222+
# Create 802.1ad vlan via bridge in host
223+
test.log.info("Create 802.1ad vlan via bridge %s", bridge_name)
224+
advlan_ifname = params["advlan_name"]
225+
add_advlan_cmd = params["add_advlan_cmd"]
226+
process.run(add_advlan_cmd)
227+
advlan_iface = utils_net.Interface(advlan_ifname)
228+
advlan_iface.set_mac(params["advlan_mac"])
229+
process.run(set_ip_cmd % (params["advlan_ip"], advlan_ifname))
230+
advlan_iface.up()
231+
output = process.getoutput("ip addr show %s" % advlan_ifname)
232+
test.log.info(output)
233+
234+
# Ping guest from host via 802.1ad vlan interface
235+
test.log.info("Start ping test from host to %s via %s", L1tag_iface_ip, advlan_ifname)
236+
ping_count = int(params.get("ping_count"))
237+
status, output = utils_net.ping(
238+
L1tag_iface_ip,
239+
ping_count,
240+
interface=advlan_ifname,
241+
timeout=float(ping_count) * 1.5,
242+
)
243+
if status != 0:
244+
test.fail("Ping returns non-zero value %s" % output)
245+
package_lost = utils_test.get_loss_ratio(output)
246+
if package_lost != 0:
247+
test.fail(
248+
"%s packeage lost when ping guest ip %s "
249+
% (package_lost, L1tag_iface_ip)
250+
)
251+
252+
# Stop tcpdump and check result
253+
session.cmd_output_safe("pkill tcpdump")
254+
check_tcpdump_result(session, L1tag_iface, "ethertype IPv4 (0x0800)")
255+
check_tcpdump_result(
256+
session, nic_name, "ethertype 802.1Q-QinQ (0x88a8)", vlan_tag="vlan 10,"
257+
)
258+
259+
# Set IP on L2 tag on the guest interface with vid 20
260+
L2tag_iface = params["L2tag_iface"]
261+
L2tag_iface_ip = params["L2tag_iface_ip"]
262+
session.cmd_output(set_ip_cmd % (L2tag_iface_ip, L2tag_iface))
263+
session.cmd("ip link set %s up" % L2tag_iface)
264+
output = session.cmd_output("ip addr show %s" % L2tag_iface, timeout=120)
265+
test.log.info(output)
266+
267+
# Start tcpdump on L1tag and L2tag interfaces and first_nic in guest
268+
test.log.info("Start tcpdump in %s", vm_name)
269+
L2tag_tcpdump_log = params.get("tcpdump_log") % L2tag_iface
270+
L2tag_tcpdump_cmd = params.get("tcpdump_cmd") % (L2tag_iface, L2tag_tcpdump_log)
271+
session.sendline(L1tag_tcpdump_cmd)
272+
time.sleep(2)
273+
session.sendline(L2tag_tcpdump_cmd)
274+
time.sleep(2)
275+
session.sendline(first_nic_tcpdump_cmd)
276+
time.sleep(5)
277+
278+
# Create 802.1q vlan via 802.1ad vlan in host
279+
test.log.info("Create 802.1q vlan via 802.1ad vlan %s", advlan_ifname)
280+
qvlan_ifname = params["qvlan_name"]
281+
add_qvlan_cmd = params["add_qvlan_cmd"]
282+
process.system_output(add_qvlan_cmd)
283+
qvlan_iface = utils_net.Interface(qvlan_ifname)
284+
process.system(set_ip_cmd % (params["qvlan_ip"], qvlan_ifname))
285+
qvlan_iface.up()
286+
output = process.getoutput("ip addr show %s" % qvlan_ifname)
287+
test.log.info(output)
288+
289+
# Ping guest from host via 802.1q vlan interface
290+
test.log.info("Start ping test from host to %s via %s", L2tag_iface_ip, qvlan_ifname)
291+
status, output = utils_net.ping(
292+
L2tag_iface_ip,
293+
ping_count,
294+
interface=qvlan_ifname,
295+
timeout=float(ping_count) * 1.5,
296+
)
297+
if status != 0:
298+
test.fail("Ping returns non-zero value %s" % output)
299+
package_lost = utils_test.get_loss_ratio(output)
300+
if package_lost >= 5:
301+
test.fail(
302+
"%s packeage lost when ping guest ip %s "
303+
% (package_lost, L2tag_iface_ip)
304+
)
305+
306+
# Stop tcpdump and check result
307+
session.cmd_output_safe("pkill tcpdump")
308+
check_tcpdump_result(
309+
session, L1tag_iface, "ethertype 802.1Q (0x8100)", vlan_tag="vlan 20,"
310+
)
311+
check_tcpdump_result(session, L2tag_iface, "ethertype IPv4 (0x0800)")
312+
check_tcpdump_result(
313+
session,
314+
nic_name,
315+
ethertype="ethertype 802.1Q-QinQ (0x88a8)",
316+
ethertype2="ethertype 802.1Q",
317+
vlan_tag="vlan 10,",
318+
vlan_tag2="vlan 20,",
319+
)
320+
321+
if (
322+
utils_misc.compare_qemu_version(8, 1, 0)
323+
and params.get("nic_model") == "e1000e"
324+
):
325+
session.cmd("ip link set %s mtu 1504" % nic_name)
326+
327+
# scp file to guest with L2 vlan tag
328+
cmd = "dd if=/dev/zero of=%s bs=1M count=%d" % (host_path, file_size)
329+
test.log.info("Creating %dMB file on host", file_size)
330+
process.run(cmd)
331+
test.log.info("Transferring file host -> guest, timeout: %ss", transfer_timeout)
332+
shell_port = int(params.get("shell_port", 22))
333+
334+
remote.scp_to_remote(
335+
L2tag_iface_ip, shell_port, username, password, host_path, guest_path
336+
)
337+
if not compare_host_guest_md5sum():
338+
test.fail("md5sum mismatch on guest and host")
339+
340+
finally:
341+
utils_net.delete_linux_bridge_tmux(bridge_name, host_iface)
342+
session.cmd("rm -rf %s" % guest_path, ignore_all_errors=True)
343+
virsh.destroy(vm_name)
344+
345+
# Cleanup host interfaces
346+
process.run(f"ip link del {advlan_ifname}", ignore_status=True)
347+
process.run(f"ip link del {qvlan_ifname}", ignore_status=True)
348+
349+
bk_xml.sync()

0 commit comments

Comments
 (0)