Skip to content

Commit

Permalink
Add network case of update-device:coalesce
Browse files Browse the repository at this point in the history
- VIRT-294752 - [update-device][coalesce] Live update coalesce
settings for network and bridge type interface

Signed-off-by: Haijiao Zhao <[email protected]>
  • Loading branch information
chloerh committed Feb 6, 2024
1 parent b37c57e commit 86f757e
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
- virtual_network.update_device.coalesce:
type = update_device_coalesce
host_iface =
start_vm = no
timeout = 240
outside_ip = 'www.redhat.com'
extra_attrs = {}
vm_ping_outside = pass
variants:
- delete_iface_coalesce:
rx_frames = 32
coalesce = {'coalesce': {'max': '${rx_frames}'}}
- add_iface_coalesce:
coalesce = {}
updated_rx_frames = 64
updated_coalesce = {'coalesce': {'max': '${updated_rx_frames}'}}
- update_iface_coalesce:
rx_frames = 64
coalesce = {'coalesce': {'max': '${rx_frames}'}}
updated_rx_frames = 32
updated_coalesce = {'coalesce': {'max': '${updated_rx_frames}'}}
variants:
- nat_net:
iface_type = network
iface_source = {'source': {'network': 'default'}}
- linux_br:
iface_type = bridge
br_type = linux_br
iface_source = {'source': {'bridge': br_name}}
- ovs_br:
iface_type = bridge
br_type = ovs_br
iface_source = {'source': {'bridge': br_name}}
extra_attrs = {'virtualport': {'type': 'openvswitch'}}
iface_attrs = {'type_name': '${iface_type}', **${coalesce}, **${iface_source}, 'model': 'virtio', 'mac_address': mac, **${extra_attrs}}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def run(test, params, env):
vm.start()
vm.wait_for_serial_login().close()

iface = network_base.get_iface_xml_inst(vmxml, 'on VM')
iface = network_base.get_iface_xml_inst(vm_name, 'on VM')
iface_original = iface.copy()
if del_attr:
if del_attr == 'boot':
Expand All @@ -64,7 +64,7 @@ def run(test, params, env):
if err_msg:
libvirt.check_result(up_result, err_msg)

iface_update = network_base.get_iface_xml_inst(vmxml,
iface_update = network_base.get_iface_xml_inst(vm_name,
'after update-device')
if iface_update != iface_original:
test.fail(f'Interface xml changed after unsuccessful update.\n'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import logging

from avocado.utils import process
from virttest import utils_misc
from virttest import utils_net
from virttest import virsh
from virttest.libvirt_xml import vm_xml
from virttest.utils_libvirt import libvirt_vmxml
from virttest.utils_test import libvirt

from provider.virtual_network import network_base

VIRSH_ARGS = {'ignore_status': False, 'debug': True}

LOG = logging.getLogger('avocado.' + __name__)


def check_coalesce_rx_frames(tap_device, rx_frames, test):
"""
Check whether coalesce rx-frames meets expectation
:param tap_device: tap device to be checked
:param rx_frames: expected rx-frames
:param test: test instance
"""
coal_params = network_base.get_ethtool_coalesce(tap_device)
LOG.debug(f'coalesce parameters from ethtool: {coal_params}')
coal_rx_frames = coal_params.get('rx-frames')
if coal_rx_frames != rx_frames:
test.fail(f'rx-frames of {tap_device} should be {rx_frames}, '
f'not {coal_rx_frames}')


def run(test, params, env):
"""
Test update-device command to update coalesce of interface
"""
vm_name = params.get('main_vm')
vm = env.get_vm(vm_name)
rand_id = utils_misc.generate_random_string(3)
br_type = params.get('br_type', '')
br_name = br_type + '_' + rand_id
mac = utils_net.generate_mac_address_simple()
iface_attrs = eval(params.get('iface_attrs', '{}'))
host_iface = params.get('host_iface')
host_iface = host_iface if host_iface else utils_net.get_net_if(
state='UP')[0]
rx_frames = params.get('rx_frames', '0')
updated_rx_frames = params.get('updated_rx_frames', '0')
updated_coalesce = eval(params.get('updated_coalesce', '{}'))

vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
bkxml = vmxml.copy()

try:
LOG.info('Create bridge for test.')
if br_type == 'linux_br':
utils_net.create_linux_bridge_tmux(br_name, host_iface)
process.run(f'ip l show type bridge {br_name}', shell=True)
elif br_type == 'ovs_br':
utils_net.create_ovs_bridge(br_name)

LOG.info('Setup interface on vm.')
vmxml.del_device('interface', by_tag=True)
libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_attrs)
LOG.debug(f'VMXML of {vm_name}:\n{virsh.dumpxml(vm_name).stdout_text}')

vm.start()
session = vm.wait_for_serial_login()

LOG.info('Check the rx-frames value for the tap device on the host.')
iflist = libvirt.get_interface_details(vm_name)
tap_device = iflist[0]['interface']
check_coalesce_rx_frames(tap_device, rx_frames, test)

LOG.info('Prepare interface xml to be updated with.')
iface = network_base.get_iface_xml_inst(vm_name, 'on VM')
if not updated_coalesce:
iface.del_coalesce()
else:
iface.setup_attrs(**updated_coalesce)

virsh.update_device(vm_name, iface.xml, **VIRSH_ARGS)

LOG.info('Check the live xml is updated.')
iface_update = network_base.get_iface_xml_inst(
vm_name, 'after update-device')
expect_coalesce = updated_coalesce.get('coalesce')
network_base.check_iface_attrs(iface_update, 'coalesce',
expect_coalesce)

LOG.info('Check the rx-frames value for the tap device on the host.')
check_coalesce_rx_frames(tap_device, updated_rx_frames, test)

LOG.info('Login vm to check whether the network works well via ping.')
ips = {'outside_ip': params.get('outside_ip')}
network_base.ping_check(params, ips, session, force_ipv4=True)

finally:
if 'session' in locals():
session.close()
bkxml.sync()
if br_type == 'linux_br':
LOG.debug(f'Delete linux bridge: {br_name}')
utils_net.delete_linux_bridge_tmux(br_name, host_iface)
if br_type == 'ovs_br':
LOG.debug(f'Delete ovs bridge: {br_name}')
utils_net.delete_ovs_bridge(br_name)
39 changes: 34 additions & 5 deletions provider/virtual_network/network_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@
import shutil

import aexpect

from avocado.core import exceptions
from avocado.utils import process

from virttest import remote
from virttest import utils_net
from virttest import virsh

from virttest.libvirt_xml import network_xml
from virttest.libvirt_xml import vm_xml

VIRSH_ARGS = {'ignore_status': False, 'debug': True}

Expand Down Expand Up @@ -266,15 +264,46 @@ def set_static_ip(iface, ip, netmask, session):
session.cmd(f'ifconfig {iface} {ip}/{netmask}')


def get_iface_xml_inst(vmxml, comment, index=0):
def get_iface_xml_inst(vm_name, comment, index=0):
"""
Get iface xml instance with given vm and index
:param vmxml: xml instance of vm
:param vm_name: name of vm
:param comment: comment to log
:param index: index of interface on vm, defaults to 0
:return: xml instance of interface
"""
vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name)
iface = vmxml.get_devices('interface')[index]
LOG.debug(f'Interface xml ({comment}):\n{iface}')
return iface


def get_ethtool_coalesce(iface):
"""
Get coalesce parameters from ethtool command output
:param iface: interface name
:return: dict-type coalesce parameters
"""
eth_out = process.run(f'ethtool -c {iface}').stdout_text
items = [x.split(':') for x in eth_out.replace('\t', '').splitlines() if x]
coalesce = {item[0]: item[1] for item in items[1:] if len(item) == 2}

return coalesce


def check_iface_attrs(iface, key, expect_val):
"""
Check whether interface attribute value meets expectation
:param iface: interface name
:param key: interface attribute key
:param expect_val: expect attribute value
"""
actual_val = iface.fetch_attrs().get(key)
LOG.debug(f'Expect {key}: {expect_val}\n'
f'Actual {key}: {actual_val}')
if actual_val != expect_val:
raise exceptions.TestFail(f'Updated {key} of iface should be '
f'{expect_val}, NOT {actual_val}')

0 comments on commit 86f757e

Please sign in to comment.