Skip to content

Commit fb02151

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 fb02151

File tree

3 files changed

+436
-0
lines changed

3 files changed

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

0 commit comments

Comments
 (0)