[dts] [‘dts-v1’ 4/9] Add VM class and the virtual DUT class and the virtual resource module

Jiajia, SunX sunx.jiajia at intel.com
Tue May 19 07:46:33 CEST 2015



> -----Original Message-----
> From: Liu, Yong
> Sent: Monday, May 18, 2015 9:58 PM
> To: Jiajia, SunX; dts at dpdk.org
> Subject: RE: [dts] [‘dts-v1’ 4/9] Add VM class and the virtual DUT
> class and the virtual resource module
> 
> Jiajia, please see my comments below.
> This patch is so huge and when edit this email sometime my outlook hang
> up. Can you separated this patch into two or three patches?
> 
> > -----Original Message-----
> > From: dts [mailto:dts-bounces at dpdk.org] On Behalf Of sjiajiax
> > Sent: Monday, May 18, 2015 1:07 PM
> > To: dts at dpdk.org
> > Subject: [dts] [‘dts-v1’ 4/9] Add VM class and the virtual DUT class
> and
> > the virtual resource module
> >
> > Signed-off-by: sjiajiax <sunx.jiajia at intel.com>
> > ---
> >  framework/qemu_kvm.py      | 912
> > +++++++++++++++++++++++++++++++++++++++++++++
> >  framework/virt_base.py     | 250 +++++++++++++
> >  framework/virt_dut.py      | 239 ++++++++++++
> >  framework/virt_resource.py | 486 ++++++++++++++++++++++++
> >  4 files changed, 1887 insertions(+)
> >  create mode 100644 framework/qemu_kvm.py
> >  create mode 100644 framework/virt_base.py
> >  create mode 100644 framework/virt_dut.py
> >  create mode 100644 framework/virt_resource.py
> >
> > diff --git a/framework/qemu_kvm.py b/framework/qemu_kvm.py
> > new file mode 100644
> > index 0000000..5f5f665
> > --- /dev/null
> > +++ b/framework/qemu_kvm.py
> > @@ -0,0 +1,912 @@
> > +# <COPYRIGHT_TAG>
> > +
> > +import time
> > +import re
> > +import os
> > +
> > +from virt_base import VirtBase
> > +from exception import StartVMFailedException
> > +
> > +# This name is derictly defined in the qemu guest serivce
> > +# So you can not change it except it is changed by the service
> > +QGA_DEV_NAME = 'org.qemu.guest_agent.0'
> > +# This path defines an socket path on the host connected with
> > +# a specified VM
> > +QGA_SOCK_PATH_TEMPLATE = '/tmp/%(vm_name)s_qga0.sock'
> > +
> > +
> > +class QEMUKvm(VirtBase):
> > +
> > +    DEFAULT_BRIDGE = 'br0'
> > +    QEMU_IFUP = """#!/bin/sh
> > +
> > +set -x
> > +
> > +switch=%(switch)s
> > +
> > +if [ -n "$1" ];then
> > +    tunctl -t $1
> > +    ip link set $1 up
> > +    sleep 0.5s
> > +    brctl addif $switch $1
> > +    exit 0
> > +else
> > +    echo "Error: no interface specified"
> > +    exit 1
> > +fi
> > +"""
> 
> If this file not changed, can be just moved into dep folder. This will
> make this module more clear.
> 

Ok, it will be moved into the dep folder in the next version.

> > +    QEMU_IFUP_PATH = '/etc/qemu-ifup'
> > +
> > +    def __init__(self, dut, vm_name, suite_name):
> > +        super(QEMUKvm, self).__init__(dut, vm_name, suite_name)
> Can we auto-detected suite name? In test case we should not use hard
> code suite name.
> 
> > +        self.set_vm_name(self.vm_name)
> > +        self.set_vm_enable_kvm()
> > +        self.set_vm_qga()
> > +        self.set_vm_daemon()
> > +
> 
> It's better to use one function "set_vm_default" to replace these
> functions.
> 

Ok, it will be changed.

> > +        # initialize qemu emulator, example: qemu-system-x86_64
> > +        self.qemu_emulator = self.get_qemu_emulator()
> > +
> > +        # initialize qemu boot command line
> > +        # example: qemu-system-x86_64 -name vm1 -m 2048 -vnc :1 -
> > daemonize
> > +        self.whole_qemu_kvm_boot_line = ''
> > +
> 
> The name is too long, please narrow it like "self.qemu_commmandline".
> 

Ok, I will try.

> > +        self.init_vm_request_resource()
> 
> Please add some description of this function.

It will be done next version.

> > +
> > +        QGA_CLI_PATH = '-r dep/QMP/'
> > +        self.host_session.copy_file_to(QGA_CLI_PATH)
> > +
> > +    def init_vm_request_resource(self):
> > +        """
> > +        initialize vcpus what will be pinned to the VM.
> > +        If specify this param, the specified vcpus will
> > +        be pinned to VM by the command 'taskset' when
> > +        starting the VM.
> > +        example:
> > +            vcpus_pinned_to_vm = '1 2 3 4'
> > +            taskset -c 1,2,3,4 qemu-boot-command-line
> > +        """
> > +        self.vcpus_pinned_to_vm = ''
> > +
> > +        # initialize assigned PCI
> > +        self.assigned_pcis = []
> > +
> > +    def get_virt_type(self):
> > +        """
> > +        Get the virtual type.
> > +        """
> > +        return 'KVM'
> > +
> > +    def get_qemu_emulator(self):
> > +        """
> > +        Get the qemu emulator based on the crb.
> > +        """
> > +        arch = self.host_session.send_expect('uname -m', '# ')
> > +        return 'qemu-system-' + arch
> > +
> > +    def set_qemu_emulator(self, qemu_emulator):
> > +        """
> > +        Set the qemu emulator explicitly.
> > +        """
> > +        out = self.host_session.send_expect(
> > +            'whereis %s' % str(qemu_emulator), '[.*')
> > +        command_paths = out.split(':')[1:]
> > +        if command_paths[0].lstrip():
> > +            print "No emulator [ %s ] on the DUT [ %s ]" % \
> > +                (qemu_emulator, self.host_dut.get_ip_address())
> > +            return None
> > +        self.qemu_emulator = qemu_emulator
> > +
> This function not called by dts. If this function is for explicated
> qemu binary, there's no meaningful to use "whereis" find qemu.
> 

Yes, you are right, I will try to find another tool to replace it.

> > +    def has_virtual_ability(self):
> > +        """
> > +        Check if host has the virtual ability.
> > +        """
> > +        out = self.host_session.send_expect('lsmod | grep kvm', '# ')
> > +        if 'kvm' in out and 'kvm_intel' in out:
> > +            return True
> > +        else:
> > +            return False
> > +
> 
> We should also check whether "vmx" supported in cpuinfo.
> 

Right, I lose it, I will add it in the next version.

> > +    def enable_virtual_ability(self):
> > +        """
> > +        Load the virutal module of kernel to enable the virutal
> ability.
> > +        """
> > +        self.host_session.send_expect('modprobe kvm', '# ')
> > +        self.host_session.send_expect('modprobe kvm_intel', '# ')
> > +        return True
> > +
> > +    def disk_image_is_ok(self, image):
> > +        """
> > +        Check if the image is OK and no error.
> > +        """
> > +        pass
> > +
> > +    def image_is_used(self, image_path):
> > +        """
> > +        Check if the image has been used on the host.
> > +        """
> > +        qemu_cmd_lines = self.host_session.send_expect(
> > +            "ps aux | grep qemu | grep -v grep", "# ")
> > +
> > +        image_name_flag = '/' + image_path.strip().split('/')[-1] +
> ' '
> > +        if image_path in qemu_cmd_lines or \
> > +                image_name_flag in qemu_cmd_lines:
> > +            return True
> > +        return False
> > +
> > +    def __add_boot_line(self, option_boot_line):
> > +        """
> > +        Add boot option into the boot line.
> > +        """
> > +        separator = ' '
> > +        self.whole_qemu_kvm_boot_line += separator +
> option_boot_line
> > +
> > +    def set_vm_enable_kvm(self, enable='yes'):
> > +        """
> > +        Set VM boot option to enable the option 'enable-kvm'.
> > +        """
> > +        self.params.append({'enable_kvm': [{'enable': '%s' %
> enable}]})
> > +
> > +    def add_vm_enable_kvm(self, **options):
> > +        """
> > +        'enable': 'yes'
> > +        """
> > +        if 'enable' in options.keys() and \
> > +                options['enable'] == 'yes':
> > +            enable_kvm_boot_line = '-enable-kvm'
> > +            self.__add_boot_line(enable_kvm_boot_line)
> > +
> > +    def set_vm_name(self, vm_name):
> > +        """
> > +        Set VM name.
> > +        """
> > +        self.params.append({'name': [{'name': '%s' % vm_name}]})
> > +
> > +    def add_vm_name(self, **options):
> > +        """
> > +        name: vm1
> > +        """
> > +        if 'name' in options.keys() and \
> > +                options['name']:
> > +            name_boot_line = '-name %s' % options['name']
> > +            self.__add_boot_line(name_boot_line)
> > +
> > +    def add_vm_cpu(self, **options):
> > +        """
> > +        model: [host | core2duo | ...]
> > +               usage:
> > +                    choose model value from the command
> > +                        qemu-system-x86_64 -cpu help
> > +        number: '4' #number of vcpus
> > +        cpupin: '3 4 5 6' # host cpu list
> > +        """
> > +        if 'model' in options.keys() and \
> > +                options['model']:
> > +            cpu_boot_line = '-cpu %s' % options['model']
> > +            self.__add_boot_line(cpu_boot_line)
> > +        if 'number' in options.keys() and \
> > +                options['number']:
> > +            smp_cmd_line = '-smp %d' % int(options['number'])
> > +            self.__add_boot_line(smp_cmd_line)
> > +        if 'cpupin' in options.keys() and \
> > +                options['cpupin']:
> > +            self.vcpus_pinned_to_vm = str(options['cpupin'])
> > +
> > +    def add_vm_mem(self, **options):
> > +        """
> > +        size: 1024
> > +        """
> > +        if 'size' in options.keys():
> > +            mem_boot_line = '-m %s' % options['size']
> > +            self.__add_boot_line(mem_boot_line)
> > +
> > +    def add_vm_disk(self, **options):
> > +        """
> > +        file: /home/image/test.img
> > +        """
> > +        if 'file' in options.keys():
> > +            disk_boot_line = '-drive file=%s' % options['file']
> > +            self.__add_boot_line(disk_boot_line)
> > +
> > +    def add_vm_net(self, **options):
> > +        """
> > +        Add VM net device.
> > +        type: [nic | user | tap | bridge | ...]
> > +        opt_[vlan | fd | br | mac | ...]
> > +            note:the sub-option will be decided according to the net
> type.
> > +        """
> > +        if 'type' in options.keys():
> > +            if 'opt_vlan' not in options.keys():
> > +                options['opt_vlan'] = '0'
> > +            if options['type'] == 'nic':
> > +                self.__add_vm_net_nic(**options)
> > +            if options['type'] == 'user':
> > +                self.__add_vm_net_user(**options)
> > +            if options['type'] == 'tap':
> > +                self.__add_vm_net_tap(**options)
> > +
> > +            if options['type'] == 'user':
> > +                self.net_type = 'hostfwd'
> > +            elif options['type'] in ['tap', 'bridge']:
> > +                self.net_type = 'bridge'
> > +
> 
> Element "net_type" not used, why add this here?
> 

When trying to get Guest IP, it will be used. 

> > +    def __add_vm_net_nic(self, **options):
> > +        """
> > +        type: nic
> > +        opt_vlan: 0
> > +            note: Default is 0.
> > +        opt_macaddr: 00:00:00:00:01:01
> > +            note: if creating a nic, it`s better to specify a MAC,
> > +                  else it will get a random number.
> > +        opt_model:["e1000" | "virtio" | "i82551" | ...]
> > +            note: Default is e1000.
> > +        opt_name: 'nic1'
> > +        opt_addr: ''
> > +            note: PCI cards only.
> > +        opt_vectors:
> > +            note: This option currently only affects virtio cards.
> > +        """
> > +        net_boot_line = '-net nic'
> > +        separator = ','
> > +        if 'opt_vlan' in options.keys() and \
> > +                options['opt_vlan']:
> > +            net_boot_line += separator + 'vlan=%s' %
> options['opt_vlan']
> > +
> > +        # add MAC info
> > +        if 'opt_macaddr' in options.keys() and \
> > +                options['opt_macaddr']:
> > +            mac = options['opt_macaddr']
> > +        else:
> > +            mac = self.generate_unique_mac()
> > +        net_boot_line += separator + 'macaddr=%s' % mac
> > +
> > +        if 'opt_model' in options.keys() and \
> > +                options['opt_model']:
> > +            net_boot_line += separator + 'model=%s' %
> options['opt_model']
> > +        if 'opt_name' in options.keys() and \
> > +                options['opt_name']:
> > +            net_boot_line += separator + 'name=%s' %
> options['opt_name']
> > +        if 'opt_addr' in options.keys() and \
> > +                options['opt_addr']:
> > +            net_boot_line += separator + 'addr=%s' %
> options['opt_addr']
> > +        if 'opt_vectors' in options.keys() and \
> > +                options['opt_vectors']:
> > +            net_boot_line += separator + 'vectors=%s' %
> > options['opt_vectors']
> > +
> > +        if self.__string_has_multi_fields(net_boot_line, separator):
> > +            self.__add_boot_line(net_boot_line)
> > +
> > +    def __add_vm_net_user(self, **options):
> > +        """
> > +        type: user
> > +        opt_vlan: 0
> > +            note: default is 0.
> > +        opt_hostfwd: [tcp|udp]:[hostaddr]:hostport-
> [guestaddr]:guestport
> > +        """
> > +        net_boot_line = '-net user'
> > +        separator = ','
> > +        if 'opt_vlan' in options.keys() and \
> > +                options['opt_vlan']:
> > +            net_boot_line += separator + 'vlan=%s' %
> options['opt_vlan']
> > +        if 'opt_hostfwd' in options.keys() and \
> > +                options['opt_hostfwd']:
> > +            self.__check_net_user_opt_hostfwd(options['opt_hostfwd'])
> > +            opt_hostfwd = options['opt_hostfwd']
> > +        else:
> > +            opt_hostfwd = '::-:'
> > +        hostfwd_line = self.__parse_net_user_opt_hostfwd(opt_hostfwd)
> > +        net_boot_line += separator + 'hostfwd=%s' % hostfwd_line
> > +
> > +        if self.__string_has_multi_fields(net_boot_line, separator):
> > +            self.__add_boot_line(net_boot_line)
> > +
> > +    def __check_net_user_opt_hostfwd(self, opt_hostfwd):
> > +        """
> > +        Use regular expression to check if hostfwd value format is
> > correct.
> > +        """
> > +        regx_ip = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
> > +        regx_hostfwd = r'["tcp" | "udp"]?:%s?:\d+-%s?:\d+' %
> (regx_ip,
> > regx_ip)
> > +        if not re.match(regx_hostfwd, opt_hostfwd):
> > +            raise Exception("Option opt_hostfwd format is not
> correct,\n"
> > +
> > +                            "it is %s,\n " % opt_hostfwd +
> > +                            "it should be
> [tcp|udp]:[hostaddr]:hostport-"
> > +
> > +                            "[guestaddr]:guestport.\n")
> > +
> > +    def __parse_net_user_opt_hostfwd(self, opt_hostfwd):
> > +        """
> > +        Parse the boot option 'hostfwd'.
> > +        """
> > +        separator = ':'
> > +        field = lambda option, index, separator=':': \
> > +            option.split(separator)[index]
> > +
> > +        # get the forword type
> > +        fwd_type = field(opt_hostfwd, 0)
> > +        if not fwd_type:
> > +            fwd_type = 'tcp'
> > +
> > +        # get the host addr
> > +        host_addr = field(opt_hostfwd, 1)
> > +        if not host_addr:
> > +            host_addr = str(self.host_dut.get_ip_address())
> > +
> > +        # get the host port in the option
> > +        host_port = field(opt_hostfwd, 2).split('-')[0]
> > +        if not host_port:
> > +            host_port = str(self.virt_pool.alloc_port(self.vm_name))
> > +        self.redir_port = host_port
> > +
> > +        # get the guest addr
> > +        try:
> > +            guest_addr = str(field(opt_hostfwd, 2).split('-')[1])
> > +        except IndexError as e:
> > +            guest_addr = ''
> > +
> > +        # get the guest port in the option
> > +        guest_port = str(field(opt_hostfwd, 3))
> > +        if not guest_port:
> > +            guest_port = '22'
> > +
> > +        hostfwd_line = fwd_type + separator + \
> > +            host_addr + separator + \
> > +            host_port + \
> > +            '-' + \
> > +            guest_addr + separator + \
> > +            guest_port
> > +
> > +        # init the redirect incoming TCP or UDP connections
> > +        # just combine host address and host port, it is enough
> > +        # for using ssh to connect with VM
> > +        self.hostfwd_addr = host_addr + separator + host_port
> > +
> > +        return hostfwd_line
> > +
> > +    def __add_vm_net_tap(self, **options):
> > +        """
> > +        type: tap
> > +        opt_vlan: 0
> > +            note: default is 0.
> > +        opt_br: br0
> > +            note: if choosing tap, need to specify bridge name,
> > +                  else it will be br0.
> > +        opt_script: QEMU_IFUP_PATH
> > +            note: if not specified, default is self.QEMU_IFUP_PATH.
> > +        opt_downscript: QEMU_IFDOWN_PATH
> > +            note: if not specified, default is self.QEMU_IFDOWN_PATH.
> > +        """
> > +        net_boot_line = '-net tap'
> > +        separator = ','
> > +
> > +        # add bridge info
> > +        if 'opt_br' in options.keys() and \
> > +                options['opt_br']:
> > +            bridge = options['opt_br']
> > +        else:
> > +            bridge = self.DEFAULT_BRIDGE
> > +        self.__generate_net_config_script(str(bridge))
> > +
> > +        if 'opt_vlan' in options.keys() and \
> > +                options['opt_vlan']:
> > +            net_boot_line += separator + 'vlan=%s' %
> options['opt_vlan']
> > +
> > +        # add network configure script path
> > +        if 'opt_script' in options.keys() and \
> > +                options['opt_script']:
> > +            script_path = options['opt_script']
> > +        else:
> > +            script_path = self.QEMU_IFUP_PATH
> > +        net_boot_line += separator + 'script=%s' % script_path
> > +
> > +        # add network configure downscript path
> > +        if 'opt_downscript' in options.keys() and \
> > +                options['opt_downscript']:
> > +            net_boot_line += separator + \
> > +                'downscript=%s' % options['opt_downscript']
> > +
> > +        if self.__string_has_multi_fields(net_boot_line, separator):
> > +            self.__add_boot_line(net_boot_line)
> > +
> > +    def __generate_net_config_script(self, switch=DEFAULT_BRIDGE):
> > +        """
> > +        Generate a script for qemu emulator to build a tap device
> > +        between host and guest.
> > +        """
> > +        qemu_ifup = self.QEMU_IFUP % {'switch': switch}
> > +        file_name = os.path.basename(self.QEMU_IFUP_PATH)
> > +        tmp_file_path = '/tmp/%s' % file_name
> > +        self.host_dut.create_file(qemu_ifup, tmp_file_path)
> > +        self.host_session.send_expect('mv -f ~/%s %s' % (file_name,
> > +
> > self.QEMU_IFUP_PATH), '# ')
> > +        self.host_session.send_expect(
> > +            'chmod +x %s' % self.QEMU_IFUP_PATH, '# ')
> > +
> > +    def set_vm_device(self, driver='pci-assign', **props):
> > +        """
> > +        Set VM device with specified driver.
> > +        """
> > +        props['driver'] = driver
> > +        index = self.find_option_index('device')
> > +        if index:
> > +            self.params[index]['device'].append(props)
> > +        else:
> > +            self.params.append({'device': [props]})
> > +
> > +    def add_vm_device(self, **options):
> > +        """
> > +        driver: [pci-assign | virtio-net-pci | ...]
> > +        prop_[host | addr | ...]: value
> > +            note:the sub-property will be decided according to the
> driver.
> > +        """
> > +        if 'driver' in options.keys() and \
> > +                options['driver']:
> > +            if options['driver'] == 'pci-assign':
> > +                self.__add_vm_pci_assign(**options)
> > +            elif options['driver'] == 'virtio-net-pci':
> > +                self.__add_vm_virtio_net_pci(**options)
> > +
> > +    def __add_vm_pci_assign(self, **options):
> > +        """
> > +        driver: pci-assign
> > +        prop_host: 08:00.0
> > +        prop_addr: 00:00:00:00:01:02
> > +        """
> > +        dev_boot_line = '-device pci-assign'
> > +        separator = ','
> > +        if 'prop_host' in options.keys() and \
> > +                options['prop_host']:
> > +            dev_boot_line += separator + 'host=%s' %
> options['prop_host']
> > +        if 'prop_addr' in options.keys() and \
> > +                options['prop_addr']:
> > +            dev_boot_line += separator + 'addr=%s' %
> options['prop_addr']
> > +            self.assigned_pcis.append(options['prop_addr'])
> > +
> > +        if self.__string_has_multi_fields(dev_boot_line, separator):
> > +            self.__add_boot_line(dev_boot_line)
> > +
> > +    def __add_vm_virtio_net_pci(self, **options):
> > +        """
> > +        driver: virtio-net-pci
> > +        prop_netdev: mynet1
> > +        prop_id: net1
> > +        prop_mac: 00:00:00:00:01:03
> > +        prop_bus: pci.0
> > +        prop_addr: 0x3
> > +        """
> > +        dev_boot_line = '-device virtio-net-pci'
> > +        separator = ','
> > +        if 'prop_netdev' in options.keys() and \
> > +                options['prop_netdev']:
> > +            dev_boot_line += separator + 'netdev=%s' %
> > options['prop_netdev']
> > +        if 'prop_id' in options.keys() and \
> > +                options['prop_id']:
> > +            dev_boot_line += separator + 'id=%s' % options['prop_id']
> > +        if 'prop_mac' in options.keys() and \
> > +                options['prop_mac']:
> > +            dev_boot_line += separator + 'mac=%s' %
> options['prop_mac']
> > +        if 'prop_bus' in options.keys() and \
> > +                options['prop_bus']:
> > +            dev_boot_line += separator + 'bus=%s' %
> options['prop_bus']
> > +        if 'prop_addr' in options.keys() and \
> > +                options['prop_addr']:
> > +            dev_boot_line += separator + 'addr=%s' %
> options['prop_addr']
> > +
> > +        if self.__string_has_multi_fields(self, string, separator):
> > +            self.__add_boot_line(dev_boot_line)
> > +
> 
> What's the need  to check multi_fields? Is it enough to check whether
> configuration available?
> 

First, this function gets error params, this issue is not tested, the params should
	be 'dev_boot_line' and 'separator'.

Second, because 'dev_boot_line' is initialized with '-device virtio-net-pci', and the
	separator is ',', though there is not an option, the 'dev_boot_line' is not NULL,
	if there is no judgment to the param, we don`t know if there is a definition of 
	virtio device in the configuration.

> > +    def __string_has_multi_fields(self, string, separator,
> field_num=2):
> > +        """
> > +        Check if string has multiple fields which is splited with
> > +        specified separator.
> > +        """
> > +        fields = string.split(separator)
> > +        number = 0
> > +        for field in fields:
> > +            if field:
> > +                number += 1
> > +        if number >= field_num:
> > +            return True
> > +        else:
> > +            return False
> > +
> > +    def add_vm_monitor(self, **options):
> > +        """
> > +        port: 6061   # if adding monitor to vm, need to specicy
> > +                       this port, else it will get a free port
> > +                       on the host machine.
> > +        """
> > +        if 'port' in options.keys():
> > +            if options['port']:
> > +                port = options['port']
> > +            else:
> > +                port = self.virt_pool.alloc_port(self.vm_name)
> > +
> > +            monitor_boot_line = '-monitor tcp::%d,server,nowait' %
> > int(port)
> > +            self.__add_boot_line(monitor_boot_line)
> > +
> > +    def set_vm_qga(self, enable='yes'):
> > +        """
> > +        Set VM qemu-guest-agent.
> > +        """
> > +        index = self.find_option_index('qga')
> > +        if index:
> > +            self.params[index] = {'qga': [{'enable': '%s' % enable}]}
> > +        else:
> > +            self.params.append({'qga': [{'enable': '%s' % enable}]})
> > +        QGA_SOCK_PATH = QGA_SOCK_PATH_TEMPLATE % {'vm_name':
> self.vm_name}
> > +        self.qga_sock_path = QGA_SOCK_PATH
> > +
> > +    def add_vm_qga(self, **options):
> > +        """
> > +        enable: 'yes'
> > +        """
> > +        QGA_DEV_ID = '%(vm_name)s_qga0' % {'vm_name': self.vm_name}
> > +        QGA_SOCK_PATH = QGA_SOCK_PATH_TEMPLATE % {'vm_name':
> self.vm_name}
> > +
> > +        separator = ' '
> > +
> > +        if 'enable' in options.keys():
> > +            if options['enable'] == 'yes':
> > +                qga_boot_block = '-chardev
> > socket,path=%(SOCK_PATH)s,server,nowait,id=%(ID)s' + \
> > +                                 separator + '-device virtio-serial'
> +
> > separator + \
> > +                                 '-device
> > virtserialport,chardev=%(ID)s,name=%(DEV_NAME)s'
> > +                qga_boot_line = qga_boot_block % {'SOCK_PATH':
> > QGA_SOCK_PATH,
> > +                                                  'DEV_NAME':
> > QGA_DEV_NAME,
> > +                                                  'ID': QGA_DEV_ID}
> > +                self.__add_boot_line(qga_boot_line)
> > +                self.qga_sock_path = QGA_SOCK_PATH
> > +            else:
> > +                self.qga_sock_path = ''
> > +
> > +    def add_vm_serial_port(self, **options):
> > +        """
> > +        enable: 'yes'
> > +        """
> > +        SERAIL_SOCK_PATH = "/tmp/%s_serial.sock" % self.vm_name
> > +        if 'enable' in options.keys():
> > +            if options['enable'] == 'yes':
> > +                serial_boot_line = '-serial unix:%s,server,nowait' %
> > SERIAL_SOCK_PATH
> > +                self.__add_boot_line(serial_boot_line)
> > +            else:
> > +                pass
> > +
> > +    def add_vm_vnc(self, **options):
> > +        """
> > +        displayNum: 1
> > +        """
> > +        if 'displayNum' in options.keys() and \
> > +                options['displayNum']:
> > +            display_num = options['displayNum']
> > +        else:
> > +            display_num = self.virt_pool.alloc_vnc_num(self.vm_name)
> > +
> > +        vnc_boot_line = '-vnc :%d' % int(display_num)
> > +        self.__add_boot_line(vnc_boot_line)
> > +
> > +    def set_vm_daemon(self, enable='yes'):
> > +        """
> > +        Set VM daemon option.
> > +        """
> > +        index = self.find_option_index('daemon')
> > +        if index:
> > +            self.params[index] = {'daemon': [{'enable': '%s' %
> enable}]}
> > +        else:
> > +            self.params.append({'daemon': [{'enable': '%s' %
> enable}]})
> > +
> > +    def add_vm_daemon(self, **options):
> > +        """
> > +        enable: 'yes'
> > +            note:
> > +                By default VM will start with the daemonize status.
> > +                Not support starting it on the stdin now.
> > +        """
> > +        if 'daemon' in options.keys() and \
> > +                options['enable'] == 'no':
> > +            pass
> > +        else:
> > +            daemon_boot_line = '-daemonize'
> > +            self.__add_boot_line(daemon_boot_line)
> > +
> > +    def start_vm(self):
> > +        """
> > +        Start VM.
> > +        """
> > +        qemu_emulator = self.qemu_emulator
> > +
> > +        self.__alloc_assigned_pcis()
> > +
> > +        if self.vcpus_pinned_to_vm.strip():
> > +            vcpus = self.__alloc_vcpus()
> > +
> > +            if vcpus.strip():
> > +                whole_qemu_kvm_boot_line = 'taskset -c %s ' % vcpus
> + \
> > +                    qemu_emulator + ' ' + \
> > +                    self.whole_qemu_kvm_boot_line
> 
> If here only to get vcpus for usage, better to use function replace
> codes here.
> 

Ok, I will do it next version.

> > +        else:
> > +            whole_qemu_kvm_boot_line = qemu_emulator + ' ' + \
> > +                self.whole_qemu_kvm_boot_line
> > +
> > +        # Start VM using the qemu command
> > +        out = self.host_session.send_expect(whole_qemu_kvm_boot_line,
> '#
> > ')
> > +        time.sleep(30)
> > +        if out:
> > +            raise StartVMFailedException(out)
> > +
> > +    def __alloc_vcpus(self):
> > +        """
> > +        Allocate virtual CPUs for VM.
> > +        """
> > +        req_cpus = self.vcpus_pinned_to_vm.split()
> > +        cpus = self.virt_pool.alloc_cpu(vm=self.vm_name,
> > corelist=req_cpus)
> > +
> > +        vcpus_pinned_to_vm = ''
> > +        for cpu in cpus:
> > +            vcpus_pinned_to_vm += ',' + cpu
> > +        vcpus_pinned_to_vm = vcpus_pinned_to_vm.lstrip(',')
> > +
> > +        if len(req_cpus) != len(cpus):
> > +            print "WARNING: Just pin vcpus [ %s ] to VM!" %
> > vcpus_pinned_to_vm
> > +
> 
> If cannot allocate cpus, should raise failure.
> 

Maybe it is better to raise failure, if the user must need to get 
the cpus, Ok, I will do it next version.

> > +        return vcpus_pinned_to_vm
> > +
> > +    def __alloc_assigned_pcis(self):
> > +        """
> > +        Record the PCI device info
> > +        Struct: {dev pci: {'is_vf': [True | False],
> > +                            'pf_pci': pci}}
> > +        example:
> > +            {'08:10.0':{'is_vf':True, 'pf_pci': 08:00.0}}
> > +        """
> > +        assigned_pcis_info = {}
> > +        for pci in self.assigned_pcis:
> > +            assigned_pcis_info[pci] = {}
> > +            if self.__is_vf_pci(pci):
> > +                assigned_pcis_info[pci]['is_vf'] = True
> > +                pf_pci = self.__map_vf_to_pf(pci)
> > +                assgined_pcis_info[pci]['pf_pci'] = pf_pci
> > +                if self.virt_pool.alloc_vf_from_pf(vm=self.vm_name,
> > +                                                   pf_pci=pf_pci,
> > +                                                   *[pci]):
> > +                    port = self.__get_vf_port(pci)
> > +                    port.unbind_driver()
> > +                    port.bind_driver('pci-stub')
> > +            else:
> > +                # check that if any VF of specified PF has been
> > +                # used, raise exception
> > +                vf_pci = self.__vf_has_been_assinged(pci,
> > **assinged_pcis_info)
> > +                if vf_pci:
> > +                    raise Exception(
> > +                        "Error: A VF [%s] generated by PF [%s] has
> " %
> > +                        (vf_pci, pci) +
> > +                        "been assigned to VM, so this PF can not be
> " +
> > +                        "assigned to VM again!")
> > +                # get the port instance of PF
> > +                port = self.__get_net_device_by_pci(pci)
> > +
> > +                if self.virt_pool.alloc_pf(vm=self.vm_name,
> > +                                           *[pci]):
> > +                    port.unbind_driver()
> > +
> > +    def __is_vf_pci(self, dev_pci):
> > +        """
> > +        Check if the specified PCI dev is a VF.
> > +        """
> > +        for port_info in self.host_dut.ports_info:
> > +            if 'sriov_vfs_pci' in port_info.keys():
> > +                if dev_pci in port_info['sriov_vfs_pci']:
> > +                    return True
> > +        return False
> > +
> 
> Vf pci device should be handled in virt_dut module and shared with
> different types of virtualization hypervisor.
> 

Do you mean I should move this function to other module?

> > +    def __map_vf_to_pf(self, dev_pci):
> > +        """
> > +        Map the specified VF to PF.
> > +        """
> > +        for port_info in self.host_dut.ports_info:
> > +            if 'sriov_vfs_pci' in port_info.keys():
> > +                if dev_pci in port_info['sriov_vfs_pci']:
> > +                    return port_info['pci']
> > +        return None
> > +
> Same as above.
> 
> > +    def __get_vf_port(self, dev_pci):
> > +        """
> > +        Get the NetDevice instance of specified VF.
> > +        """
> > +        for port_info in self.host_dut.ports_info:
> > +            if 'vfs_port' in port_info.keys():
> > +                for port in port_info['vfs_port']:
> > +                    if dev_pci == port.pci:
> > +                        return port
> > +        return None
> > +
> 
> Same as above.
> > +    def __vf_has_been_assigned(self, pf_pci, **assigned_pcis_info):
> > +        """
> > +        Check if the specified VF has been used.
> > +        """
> > +        for pci in assigned_pcis_info.keys():
> > +            if assigned_pcis_info[pci]['is_vf'] and \
> > +                    assigned_pcis_info[pci]['pf_pci'] == pf_pci:
> > +                return pci
> > +        return False
> > +
> VF device can’t be shared with VMs, this function should be in resource
> module.
> 
> > +    def __get_net_device_by_pci(self, net_device_pci):
> > +        """
> > +        Get NetDevice instance by the specified PCI bus number.
> > +        """
> > +        port_info = self.host_dut.get_port_info(net_device_pci)
> > +        return port_info['port']
> > +
> 
> Vf pci device should be handled in virt_dut module and shared with
> different types of virtualization hypervisor.
> 
> > +    def get_vm_ip(self):
> > +        """
> > +        Get VM IP.
> > +        """
> > +        get_vm_ip = getattr(self, "get_vm_ip_%s" % self.net_type)
> > +        return get_vm_ip()
> > +
> > +    def get_vm_ip_hostfwd(self):
> > +        """
> > +        Get IP which VM is connected by hostfwd.
> > +        """
> > +        return self.hostfwd_addr
> > +
> > +    def get_vm_ip_bridge(self):
> > +        """
> > +        Get IP which VM is connected by bridge.
> > +        """
> > +        out = self.__control_session('ping', '60')
> > +        if not out:
> > +            time.sleep(10)
> > +            out = self.__control_session('ifconfig')
> > +            ips = re.findall(r'inet (\d+\.\d+\.\d+\.\d+)', out)
> > +
> > +            if '127.0.0.1' in ips:
> > +                ips.remove('127.0.0.1')
> > +
> > +            num = 3
> > +            for ip in ips:
> > +                out = self.host_session.send_expect(
> > +                    'ping -c %d %s' % (num, ip), '# ')
> > +                if '0% packet loss' in out:
> > +                    return ip
> 
> The first pinged interface will be the interface of bridge, can we make
> sure that?

I think it is enough for us to check if there is a connection between host 
and guest.

> > +        return ''
> > +
> > +    def __control_session(self, command, *args):
> > +        """
> > +        Use the qemu guest agent service to control VM.
> > +        Note:
> > +            :command: there are these commands as below:
> > +                       cat, fsfreeze, fstrim, halt, ifconfig, info,\
> > +                       ping, powerdown, reboot, shutdown, suspend
> > +            :args: give different args by the different commands.
> > +        """
> > +        if not self.qga_sock_path:
> > +            self.host_logger.info(
> > +                "No QGA service between host [ %s ] and guest
> [ %s ]" %
> > +                (self.host_dut.Name, self.vm_name))
> > +            return None
> > +
> > +        cmd_head = '~/QMP/' + \
> > +            "qemu-ga-client " + \
> > +            "--address=%s %s" % \
> > +            (self.qga_sock_path, command)
> > +
> > +        cmd = cmd_head
> > +        for arg in args:
> > +            cmd = cmd_head + ' ' + str(arg)
> > +
> > +        out = self.host_session.send_expect(cmd, '# ')
> > +
> > +        return out
> > +
> > +    def stop(self):
> > +        """
> > +        Stop VM.
> > +        """
> > +        self.__control_session('powerdown')
> 
> Here's need function to check whether shutdown successfully.
> 

Ok, it will be done.

> > +        time.sleep(5)
> > +        self.virt_pool.free_all_resource(self.vm_name)
> > +
> > +
> > +if __name__ == "__main__":
> > +    import subprocess
> > +    import sys
> > +    import pdb
> > +    from serializer import Serializer
> > +    from crbs import crbs
> > +    from tester import Tester
> > +    from dut import Dut
> > +    import dts
> > +    from virt_proxy import VirtProxy
> > +
> > +    command = "ifconfig br0"
> > +    subp = subprocess.Popen(command.split(), stdout=subprocess.PIPE)
> > +    subp.wait()
> > +
> > +    intf_info = subp.stdout.readlines()
> > +    for line_info in intf_info:
> > +        regx = re.search(r'inet (\d+\.\d+\.\d+\.\d+)', line_info)
> > +        if regx:
> > +            dutIP = regx.group(1)
> > +            break
> > +
> > +    print "DEBUG: dutIp: ", dutIP
> > +
> > +    # look up in crbs - to find the matching IP
> > +    crbInst = None
> > +    for crb in crbs:
> > +        if crb['IP'] == dutIP:
> > +            crbInst = crb
> > +            break
> > +
> > +    # only run on the dut in known crbs
> > +    if crbInst is None:
> > +        raise Exception("No available crb instance!!!")
> > +
> > +    # initialize the dut and tester
> > +    serializer = Serializer()
> > +    serializer.set_serialized_filename('../.%s.cache' %
> crbInst['IP'])
> > +    serializer.load_from_file()
> > +
> > +    read_cache = None
> > +    skip_setup = None
> > +
> > +    project = "dpdk"
> > +    dts.Package = 'dep/dpdk.tar.gz'
> > +    dut = dts.get_project_obj(project, Dut, crbInst, serializer)
> > +    tester = dts.get_project_obj(project, Tester, crbInst,
> serializer)
> > +    dut.tester = tester
> > +    dut.base_dir = 'dpdk'
> > +    dut.set_nic_type('niantic')
> > +    tester.dut = dut
> > +
> > +    tester.set_test_types(True, False)
> > +    dut.set_test_types(True, False)
> > +
> > +    tester.set_speedup_options(read_cache, skip_setup)
> > +    tester.tester_prerequisites()
> > +    dut.set_speedup_options(read_cache, skip_setup)
> > +    dut.dut_prerequisites()
> > +
> > +    # test that generating and destroying VF
> > +    port0 = dut.ports_info[0]['port']
> > +    dut.generate_sriov_vfs_by_port(0, 4)
> > +    print "port 0 sriov vfs: ", dut.ports_info[0]
> > +
> > +    dut.destroy_sriov_vfs_by_port(0)
> > +
> > +    time.sleep(2)
> > +
> > +    # test that binding and unbing the NIC
> > +    port0_pci = dut.ports_info[0]['pci']
> > +    port0.unbind_driver()
> > +
> > +    dut.logger.info("JUST TESTING!!!")
> > +
> > +    # Start VM by the qemu kvm config file
> > +    vm1 = QEMUKvm(dut, 'vm1', 'pmd_sriov')
> > +    print "VM config params:"
> > +    print vm1.params
> > +    vm1_dut = vm1.start()
> > +
> > +    try:
> > +        host_ip = vm1.session.send_expect("ifconfig", '# ')
> > +        print "Host IP:"
> > +        print host_ip
> > +
> > +        vm1_ip = vm1.get_vm_ip()
> > +        print "VM1 IP:"
> > +        print vm1_ip
> > +
> > +        print "VM1 PCI device:"
> > +        print vm_dut.session.send_expect('lspci -nn | grep -i eth',
> '# ')
> > +    except Exception as e:
> > +        print e
> > +        vm1_dut.stop()
> > +        port0.bind_driver()
> > +    # Stop VM
> > +    vm1.stop()
> > +    port0.bind_driver()
> > +
> > +    dut.host_logger.logger_exit()
> > +    dut.logger.logger_exit()
> > +    tester.logger.logger_exit()
> > +
> > +    print "Start and stop VM over!"
> > diff --git a/framework/virt_base.py b/framework/virt_base.py
> > new file mode 100644
> > index 0000000..625c309
> > --- /dev/null
> > +++ b/framework/virt_base.py
> > @@ -0,0 +1,250 @@
> > +# <COPYRIGHT_TAG>
> > +
> > +from random import randint
> > +from itertools import imap
> > +
> > +import dts
> > +from dut import Dut
> > +from config import VirtConf
> > +from config import VIRTCONF
> > +from logger import getLogger
> > +from settings import CONFIG_ROOT_PATH
> > +from virt_dut import VirtDut
> > +
> > +
> > +class VirtBase(object):
> > +
> > +    """
> > +    Basic module for customer special virtual type. This module
> implement
> > functions
> > +    configurated and composed the VM boot command. With these
> function,
> > we can get
> > +    and set the VM boot command, and instantiate the VM.
> > +    """
> > +
> > +    def __init__(self, dut, vm_name, suite_name):
> > +        """
> > +        Initialize the VirtBase.
> > +        dut: the instance of Dut
> > +        vm_name: the name of VM which you have confiured in the
> configure
> > +        suite_name: the name of test suite
> > +        """
> > +        self.host_dut = dut
> > +        self.vm_name = vm_name
> > +        self.suite = suite_name
> > +
> > +        # init the host session and logger for VM
> > +        self.host_dut.init_host_session()
> > +
> > +        # replace dut session
> > +        self.host_session = self.host_dut.host_session
> > +        self.host_logger = self.host_dut.logger
> > +
> > +        # init the host resouce pool for VM
> > +        self.virt_pool = self.host_dut.virt_pool
> > +
> > +        if not self.has_virtual_ability():
> > +            if not self.enable_virtual_ability():
> > +                raise Exception(
> > +                    "Dut [ %s ] cannot have the virtual ability!!!")
> > +
> 
> We need handle those exception in virtualization module.
> 

I don`t think it should be handled here, because the virtual module is initialized
in the cases, if we handle this exception, how to know if the virtual module is 
initialized successfully?

Or we should define a guideline, all exceptions in the framework should be handled itself,
If failed, just return None, else return the correct result. What do you think?

> > +        self.virt_type = self.get_virt_type()
> > +        self.load_global_config()
> > +        self.load_local_config(suite_name)
> > +
> > +    def get_virt_type(self):
> > +        """
> > +        Get the virtual type, such as KVM, XEN or LIBVIRT.
> > +        """
> > +        NotImplemented
> > +
> > +    def has_virtual_ability(self):
> > +        """
> > +        Check if the host have the ability of virtualization.
> > +        """
> > +        NotImplemented
> > +
> > +    def enable_virtual_ability(self):
> > +        """
> > +        Enalbe the virtual ability on the DUT.
> > +        """
> > +        NotImplemented
> > +
> > +    def load_global_config(self):
> > +        """
> > +        Load global configure in the path DTS_ROOT_PAHT/conf.
> > +        """
> > +        conf = VirtConf(VIRTCONF)
> > +        conf.load_virt_config(self.virt_type)
> > +        self.params = conf.get_virt_config()
> > +
> Need add check whether configuration file load successfully.
> 

Yes, it should be done.

> > +    def load_local_config(self, suite_name):
> > +        """
> > +        Load local configure in the path DTS_ROOT_PATH/conf.
> > +        """
> > +        # load local configuration by suite and vm name
> > +        conf = VirtConf(CONFIG_ROOT_PATH + suite_name + '.cfg')
> > +        conf.load_virt_config(self.vm_name)
> > +        localparams = conf.get_virt_config()
> 
> Need add check whether configuration file load successfully.

Yes, it should be done.

> > +        # replace global configurations with local configurations
> > +        for param in localparams:
> > +            if 'mem' in param.keys():
> > +                self.__save_local_config('mem', param['mem'])
> > +                continue
> > +            if 'cpu' in param.keys():
> > +                self.__save_local_config('cpu', param['cpu'])
> > +                continue
> > +            # save local configurations
> > +            self.params.append(param)
> > +
> > +    def __save_local_config(self, key, value):
> > +        """
> > +        Save the local config into the global dict self.param.
> > +        """
> > +        for param in self.params:
> > +            if key in param.keys():
> > +                param[key] = value
> > +
> > +    def compose_boot_param(self):
> > +        """
> > +        Compose all boot param for starting the VM.
> > +        """
> > +        for param in self.params:
> > +            key = param.keys()[0]
> > +            value = param[key]
> > +            try:
> > +                param_func = getattr(self, 'add_vm_' + key)
> > +                if callable(param_func):
> > +                    for option in value:
> > +                        param_func(**option)
> > +                else:
> > +                    print "Virt %s function not implemented!!!" %
> key
> > +            except Exception as e:
> > +                print "Failed: ", e
> > +
> 
> Function call failed should log with error.

Ok, it will be done.

> 
> > +    def find_option_index(self, option):
> > +        """
> > +        Find the boot option in the params which is generated from
> > +        the global and local configures, and this function will
> > +        return the index by which option can be indexed in the
> > +        param list.
> > +        """
> > +        index = 0
> > +        for param in self.params:
> > +            key = param.keys()[0]
> > +            if key.strip() == option.strip():
> > +                return index
> > +            index += 1
> > +
> > +        return None
> > +
> > +    def generate_unique_mac(self):
> > +        """
> > +        Generate a unique MAC based on the DUT.
> > +        """
> > +        mac_head = '00:00:00:'
> > +        mac_tail = ':'.join(
> > +            ['%02x' % x for x in imap(lambda x:randint(0, 255),
> > range(3))])
> > +        return mac_head + mac_tail
> > +
> > +    def get_vm_ip(self):
> > +        """
> > +        Get the VM IP.
> > +        """
> > +        NotImplemented
> > +
> > +    def start(self):
> > +        """
> > +        Start VM and instantiate the VM with VirtDut.
> > +        """
> > +        self.compose_boot_param()
> > +        try:
> > +            self.start_vm()
> > +        except Exception as e:
> > +            self.host_logger.error(e)
> > +            return None
> > +        try:
> > +            vm_dut = self.instantiate_vm_dut()
> > +        except Exception as e:
> > +            self.host_logger.error(e)
> > +            self.stop()
> After stop vm, need clean up resource like VFs and cores.
> 

It should be done, this need some efforts.

> > +            return None
> > +        return vm_dut
> > +
> > +    def start_vm(self):
> > +        """
> > +        Start VM.
> > +        """
> > +        NotImplemented
> > +
> > +    def instantiate_vm_dut(self):
> > +        """
> > +        Instantiate the Dut class for VM.
> > +        """
> > +        crb = self.host_dut.crb.copy()
> > +        crb['bypass core0'] = False
> > +        vm_ip = self.get_vm_ip()
> Need check whether vm_ip valid.
> 

It should be done.

> > +        crb['IP'] = vm_ip
> > +        if ':' not in vm_ip:
> > +            remote_ip = vm_ip.strip()
> > +            redirect_port = ''
> > +        else:
> > +            remote_addr = vm_ip.split(':')
> > +            remote_ip = remote_addr[0].strip()
> > +            redirect_port = remote_addr[1].strip()
> > +        self.__remove_old_rsa_key(remote_ip, redirect_port)
> > +
> 
> These code can be moved to function "__remove_old_rsa_key".
> 

Yes, it is better.

> > +        serializer = self.host_dut.serializer
> > +
> > +        try:
> > +            vm_dut = VirtDut(
> > +                crb,
> > +                serializer,
> > +                self.virt_type,
> > +                self.vm_name,
> > +                self.suite)
> > +        except Exception as e:
> > +            raise Exception(e)
> 
> If VirtDut instantiation failed,  function instantiate_vm_dut should
> return failure and should not run remaining codes.
> 

Yes, do you mean I just need to log the error info and return failure?

> > +        vm_dut.nic_type = 'any'
> > +        vm_dut.tester = self.host_dut.tester
> > +        vm_dut.host_dut = self.host_dut
> > +        vm_dut.host_session = self.host_session
> > +
> > +        read_cache = False
> > +        skip_setup = self.host_dut.skip_setup
> > +        base_dir = self.host_dut.base_dir
> > +        vm_dut.set_speedup_options(read_cache, skip_setup)
> > +        func_only = self.host_dut.want_func_tests
> > +        perf_only = self.host_dut.want_perf_tests
> > +        vm_dut.set_test_types(func_tests=func_only,
> perf_tests=perf_only)
> > +        # base_dir should be set before prerequisites
> > +        vm_dut.set_directory(base_dir)
> > +
> > +        # setting up dpdk in vm, must call at last
> > +        vm_dut.prerequisites(dts.Package, dts.Patches)
> > +
> Prerequisites maybe failed, need add check here.
> 
> > +        target = self.host_dut.target
> > +        if target:
> > +            vm_dut.set_target(target)
> > +        else:
> > +            raise Exception("Cannot get the HOST DUT test target!")
> > +
> > +        return vm_dut
> > +
> > +    def __remove_old_rsa_key(self, remote_ip, redirect_port):
> > +        """
> > +        Remove the old RSA key of specified remote IP.
> > +        """
> > +        rsa_key_path = "~/.ssh/known_hosts"
> > +        if redirect_port:
> > +            remove_rsa_key_cmd = "sed -i '/^\[%s\]:%d/d' %s" % \
> > +                (remote_ip.strip(), int(
> > +                 redirect_port), rsa_key_path)
> > +        else:
> > +            remove_rsa_key_cmd = "sed -i '/^%s/d' %s" % \
> > +                (remote_ip.strip(), rsa_key_path)
> > +        self.host_dut.tester.send_expect(remove_rsa_key_cmd, "# ")
> > +
> > +    def stop(self):
> > +        """
> > +        Stop the VM by the name of VM.
> > +        """
> > +        NotImplemented
> > diff --git a/framework/virt_dut.py b/framework/virt_dut.py
> > new file mode 100644
> > index 0000000..1073253
> > --- /dev/null
> > +++ b/framework/virt_dut.py
> > @@ -0,0 +1,239 @@
> > +# BSD LICENSE
> > +#
> > +# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
> > +# All rights reserved.
> > +#
> > +# Redistribution and use in source and binary forms, with or without
> > +# modification, are permitted provided that the following conditions
> > +# are met:
> > +#
> > +#   * Redistributions of source code must retain the above copyright
> > +#     notice, this list of conditions and the following disclaimer.
> > +#   * Redistributions in binary form must reproduce the above
> copyright
> > +#     notice, this list of conditions and the following disclaimer
> in
> > +#     the documentation and/or other materials provided with the
> > +#     distribution.
> > +#   * Neither the name of Intel Corporation nor the names of its
> > +#     contributors may be used to endorse or promote products
> derived
> > +#     from this software without specific prior written permission.
> > +#
> > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> > +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> > +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> FOR
> > +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> > +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> > +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> > +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> USE,
> > +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> ANY
> > +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> > +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
> USE
> > +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> > +
> > +import os
> > +import re
> > +import time
> > +import dts
> > +import settings
> > +from config import PortConf
> > +from settings import NICS, LOG_NAME_SEP
> > +from ssh_connection import SSHConnection
> > +from project_dpdk import DPDKdut
> > +from dut import Dut
> > +from net_device import NetDevice
> > +from logger import getLogger
> > +
> > +
> > +class VirtDut(DPDKdut):
> > +
> > +    """
> > +    A connection to the CRB under test.
> > +    This class sends commands to the CRB and validates the responses.
> It
> > is
> > +    implemented using either ssh for linuxapp or the terminal server
> for
> > +    baremetal.
> > +    All operations are in fact delegated to an instance of either
> > CRBLinuxApp
> > +    or CRBBareMetal.
> > +    """
> > +
> > +    def __init__(self, crb, serializer, virttype, vm_name, suite):
> > +        super(Dut, self).__init__(crb, serializer)
> > +        self.vm_ip = self.get_ip_address()
> > +        self.NAME = 'virtdut' + LOG_NAME_SEP + '%s' % self.vm_ip
> > +        # load port config from suite cfg
> > +        self.suite = suite
> > +        self.logger = getLogger(self.NAME)
> > +        self.logger.config_execution('vmdut')
> > +        self.session = SSHConnection(self.vm_ip, self.NAME,
> > +                                     self.get_password())
> > +        self.session.init_log(self.logger)
> > +
> > +        # if redirect ssh port, there's only one session enabled
> > +        self.alt_session = SSHConnection(self.vm_ip, self.NAME +
> '_alt',
> > +                                         self.get_password())
> > +        self.alt_session.init_log(self.logger)
> > +
> > +        self.number_of_cores = 0
> > +        self.tester = None
> > +        self.cores = []
> > +        self.architecture = None
> > +        self.ports_info = None
> > +        self.ports_map = []
> > +        self.virttype = virttype
> > +        self.vmtype = ''
> > +        if self.virttype == 'XEN':
> > +            self.vmtype = 'domu'
> 
> Change virttype to virt_type, and why not check only by virt_type?
> What's the difference of vmtype?
> 

I need to check it with Huilong.

> > +            self.virttype = 'host'
> > +
> > +    def set_nic_type(self, nic_type):
> > +        """
> > +        Set CRB NICS ready to validated.
> > +        """
> > +        self.nic_type = nic_type
> > +        # vm_dut config will load from vm configuration file
> > +
> > +    def load_portconf(self):
> > +        """
> > +        Load port config for this virtual machine
> > +        """
> > +        return
> > +
> > +    def set_target(self, target):
> > +        """
> > +        Set env variable, these have to be setup all the time. Some
> tests
> > +        need to compile example apps by themselves and will fail
> > otherwise.
> > +        Set hugepage on DUT and install modules required by DPDK.
> > +        Configure default ixgbe PMD function.
> > +        """
> > +        self.set_toolchain(target)
> > +
> > +        # set env variable
> > +        # These have to be setup all the time. Some tests need to
> compile
> > +        # example apps by themselves and will fail otherwise.
> > +        self.send_expect("export RTE_TARGET=" + target, "#")
> > +        self.send_expect("export RTE_SDK=`pwd`", "#")
> > +
> > +        if not self.skip_setup:
> > +            self.build_install_dpdk(target)
> > +
> > +        self.setup_memory(hugepages=512)
> 512M maybe not available, this value should calculated by virtual
> machine memory size or value stripped from configuration file.
> 

You are right, it will be done next version.

> > +        self.setup_modules(target)
> > +
> > +        self.bind_interfaces_linux('igb_uio')
> 
> Module should also stripped from configuration file.
> 

What`s meaning?

> > +
> > +    def prerequisites(self, pkgName, patch):
> > +        """
> > +        Prerequest function should be called before execute any test
> case.
> > +        Will call function to scan all lcore's information which on
> DUT.
> > +        Then call pci scan function to collect nic device
> information.
> > +        At last setup DUT' environment for validation.
> > +        """
> > +        self.prepare_package(pkgName, patch)
> > +
> > +        self.send_expect("cd %s" % self.base_dir, "# ")
> > +        self.host_session.send_expect("cd %s" % self.base_dir, "# ")
> > +        self.send_expect("alias ls='ls --color=none'", "#")
> > +
> > +        if self.get_os_type() == 'freebsd':
> > +            self.send_expect('alias make=gmake', '# ')
> > +            self.send_expect('alias sed=gsed', '# ')
> > +
> We do not support freebsd guest, those code should removed.
> 

It will be done.

> > +        self.init_core_list()
> > +        self.pci_devices_information()
> > +
> > +        # scan ports before restore interface
> > +        self.scan_ports()
> > +        # restore dut ports to kernel
> > +        if self.vmtype != 'domu':
> > +            self.restore_interfaces()
> > +        else:
> > +            self.restore_interfaces_domu()
> > +        # rescan ports after interface up
> Duplicated concept with virt_type. If functions different between
> hypervisors, we need implemented them in qemu_{virt_type}.
> 

Right, it will be done.


> > +        self.rescan_ports()
> > +
> > +        # no need to rescan ports for guest os just bootup
> > +        # load port infor from config file
> > +        self.load_portconf()
> > +
> Need check whether load failed.
> 

Right, it will be done.

> > +        # enable tester port ipv6
> > +        self.host_dut.enable_tester_ipv6()
> > +        self.mount_procfs()
> > +        # auto detect network topology
> > +        self.map_available_ports()
> > +        # disable tester port ipv6
> > +        self.host_dut.disable_tester_ipv6()
> > +
> > +        # print latest ports_info
> > +        for port_info in self.ports_info:
> > +            self.logger.info(port_info)
> > +
> > +    def restore_interfaces_domu(self):
> > +        """
> > +        Restore Linux interfaces.
> > +        """
> > +        for port in self.ports_info:
> > +            pci_bus = port['pci']
> > +            pci_id = port['type']
> > +            driver = settings.get_nic_driver(pci_id)
> > +            if driver is not None:
> > +                addr_array = pci_bus.split(':')
> > +                bus_id = addr_array[0]
> > +                devfun_id = addr_array[1]
> > +                port = NetDevice(self, bus_id, devfun_id)
> 
> Port object is temporary used, why use NetDevice module create another
> one? We can just use port['port'] to use NetDevice object.

Right, it will be replaced.

> > +                itf = port.get_interface_name()
> > +                self.send_expect("ifconfig %s up" % itf, "# ")
> > +                time.sleep(30)
> 
> Sleep 30 seconds is too long and every port will wait so long. Is there
> any need to wait so long? We should call all ports up and then wait few
> seconds.

I will check it.

> > +                print self.send_expect("ip link ls %s" % itf, "# ")
> > +            else:
> > +                self.logger.info(
> > +                    "NOT FOUND DRIVER FOR PORT (%s|%s)!!!" %
> (pci_bus,
> > pci_id))
> > +
> > +    def pci_devices_information(self):
> > +        self.pci_devices_information_uncached()
> > +
> > +    def get_memory_channels(self):
> > +        """
> > +        Virtual machine has no memory channel concept, so always
> return 1
> > +        """
> > +        return 1
> > +
> > +    def check_ports_available(self, pci_bus, pci_id):
> > +        """
> > +        Check that whether auto scanned ports ready to use
> > +        """
> > +        pci_addr = "%s:%s" % (pci_bus, pci_id)
> > +        if pci_id == "8086:100e":
> > +            return False
> 
> Why e1000 default pci_id is invalided, need comments here.
> 

Ok, it will be checked.

> > +        return True
> > +        # pci_addr = "%s:%s" % (pci_bus, pci_id)
> > +        # if self.nic_type == 'any':
> > +        # load vm port conf need another function
> > +        # need add vitrual function device into NICS
> 
> Missing functions here.
> 

It should be checked here.

> > +
> > +    def scan_ports(self):
> > +        """
> > +        Scan ports information, for vm will always scan
> > +        """
> > +        self.scan_ports_uncached()
> > +
> > +    def scan_ports_uncached(self):
> > +        """
> > +        Scan ports and collect port's pci id, mac adress, ipv6
> address.
> > +        """
> > +        scan_ports_uncached = getattr(
> > +            self, 'scan_ports_uncached_%s' % self.get_os_type())
> > +        return scan_ports_uncached()
> > +
> > +    def map_available_ports(self):
> > +        """
> > +        Load or generate network connection mapping list.
> > +        """
> > +        self.map_available_ports_uncached()
> > +        self.logger.warning("DUT PORT MAP: " + str(self.ports_map))
> > +
> > +    def send_ping6(self, localPort, ipv6, mac=''):
> > +        """
> > +        Send ping6 packet from local port with destination ipv6
> address.
> > +        """
> > +        if self.ports_info[localPort]['type'] == 'ixia':
> > +            pass
> > +        else:
> > +            return self.send_expect("ping6 -w 1 -c 1 -A -I %s %s" %
> > (self.ports_info[localPort]['intf'], ipv6), "# ", 10)
> > diff --git a/framework/virt_resource.py b/framework/virt_resource.py
> > new file mode 100644
> > index 0000000..856f9dc
> > --- /dev/null
> > +++ b/framework/virt_resource.py
> > @@ -0,0 +1,486 @@
> > +#!/usr/bin/python
> > +# BSD LICENSE
> > +#
> > +# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
> > +# All rights reserved.
> > +#
> > +# Redistribution and use in source and binary forms, with or without
> > +# modification, are permitted provided that the following conditions
> > +# are met:
> > +#
> > +#   * Redistributions of source code must retain the above copyright
> > +#     notice, this list of conditions and the following disclaimer.
> > +#   * Redistributions in binary form must reproduce the above
> copyright
> > +#     notice, this list of conditions and the following disclaimer
> in
> > +#     the documentation and/or other materials provided with the
> > +#     distribution.
> > +#   * Neither the name of Intel Corporation nor the names of its
> > +#     contributors may be used to endorse or promote products
> derived
> > +#     from this software without specific prior written permission.
> > +#
> > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> > +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> > +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> FOR
> > +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> > +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> > +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> > +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> USE,
> > +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> ANY
> > +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> > +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
> USE
> > +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> > +from random import randint
> > +
> > +from utils import get_obj_funcs
> > +
> > +INIT_FREE_PORT = 6060
> > +
> > +
> > +class VirtResource(object):
> > +
> > +    """
> > +    Class handle dut resource, like cpu, memory, net devices
> > +    """
> > +
> > +    def __init__(self, dut):
> > +        self.dut = dut
> > +
> > +        self.cores = [int(core['thread']) for core in dut.cores]
> > +        # initialized unused cores
> > +        self.unused_cores = self.cores[:]
> > +        # initialized used cores
> > +        self.used_cores = [-1] * len(self.unused_cores)
> > +
> Need macro INVL replace of "-1".
> 

Ok.

> > +        self.ports_info = dut.ports_info
> > +        # initialized unused ports
> > +        self.ports = [port['pci'] for port in dut.ports_info]
> > +        self.unused_ports = self.ports[:]
> > +        # initialized used ports
> > +        self.used_ports = ['unused'] * len(self.unused_ports)
> > +
> > +        # initialized vf ports
> > +        self.vfs_info = []
> > +        self.vfs = []
> > +        self.unused_vfs = []
> > +        self.used_vfs = []
> > +
> > +        # save allocated cores and related vm
> > +        self.allocated_info = {}
> > +
> > +    def __port_used(self, pci):
> > +        index = self.ports.index(pci)
> Add check not found the pci device.
> 

Yes, it will be added.

> > +        self.used_ports[index] = pci
> > +        self.unused_ports[index] = 'used'
> > +
> > +    def __port_unused(self, pci):
> > +        index = self.ports.index(pci)
> Add check not found the pci device.

Yes, it will be added.

> > +        self.unused_ports[index] = pci
> > +        self.used_ports[index] = 'unused'
> > +
> > +    def __port_on_socket(self, pci, socket):
> > +        for port in self.ports_info:
> > +            if port['pci'] == pci:
> > +                if socket is -1:
> > +                    return True
> > +
> > +                if port['numa'] == socket:
> > +                    return True
> > +                else:
> > +                    return False
> > +
> > +        return False
> > +
> > +    def __vf_used(self, pci):
> > +        index = self.vfs.index(pci)
> Add check not found the pci device.

Yes, it will be added.

> > +        self.used_vfs[index] = pci
> > +        self.unused_vfs[index] = 'used'
> > +
> > +    def __vf_unused(self, pci):
> > +        index = self.vfs.index(pci)
> Add check not found the pci device.

Yes, it will be added.

> > +        self.used_vfs[index] = 'unused'
> > +        self.unused_vfs[index] = pci
> > +
> > +    def __core_used(self, core):
> > +        core = int(core)
> > +        index = self.cores.index(core)
> Add check not found core.

Yes, it will be added.

> > +        self.used_cores[index] = core
> > +        self.unused_cores[index] = -1
> > +
> > +    def __core_unused(self, core):
> > +        core = int(core)
> > +        index = self.cores.index(core)
> Add check not found core.

Yes, it will be added.

> > +        self.unused_cores[index] = core
> > +        self.used_cores[index] = -1
> > +
> > +    def __core_on_socket(self, core, socket):
> > +        for dut_core in self.dut.cores:
> > +            if int(dut_core['thread']) == core:
> > +                if socket is -1:
> > +                    return True
> > +
> > +                if int(dut_core['socket']) == socket:
> > +                    return True
> > +                else:
> > +                    return False
> > +
> > +        return False
> > +
> > +    def __core_isused(self, core):
> > +        index = self.cores.index(core)
> > +        if self.used_cores[index] != -1:
> > +            return True
> > +        else:
> > +            return False
> > +
> > +    def reserve_cpu(self, coremask=''):
> > +        """
> > +        Reserve dpdk used cpus by mask
> > +        """
> Add comments how to calculate cpus.
> 

Ok, it will be added.

> > +        val = int(coremask, base=16)
> > +        cpus = []
> > +        index = 0
> > +        while val != 0:
> > +            if val & 0x1:
> > +                cpus.append(index)
> > +
> > +            val = val >> 1
> > +            index += 1
> > +
> > +        for cpu in cpus:
> > +            self.__core_used(cpu)
> > +
> > +    def alloc_cpu(self, vm='', number=-1, socket=-1, corelist=None):
> > +        """
> > +        There're two options for request cpu resouce for vm.
> > +        If number is not -1, just allocate cpu from not used cores.
> > +        If list is not None, will allocate cpu after checked.
> > +        """
> > +        cores = []
> > +
> > +        if vm == '':
> > +            print "Alloc cpu request vitual machine name!!!"
> > +            return cores
> > +
> > +        if number != -1:
> > +            for core in self.unused_cores:
> > +                if core != -1 and number != 0:
> -1 should be replaced by macro INVAL.

Ok, it will be added.

> > +                    if self.__core_on_socket(core, socket) is True:
> > +                        self.__core_used(core)
> > +                        cores.append(str(core))
> > +                        number = number - 1
> > +            if number != 0:
> > +                print "Can't allocated requested cpu!!!"
> > +
> Should return error and free used cores.

Ok, it will be added.

> 
> > +        if corelist is not None:
> > +            for core in corelist:
> > +                if self.__core_isused(int(core)) is True:
> > +                    print "Core %s has been used!!!" % core
> Should return error here.
> > +                else:
> > +                    if self.__core_on_socket(int(core), socket) is
> True:
> > +                        self.__core_used(int(core))
> > +                        cores.append(core)
> > +
> > +        if vm not in self.allocated_info:
> > +            self.allocated_info[vm] = {}
> > +
> > +        self.allocated_info[vm]['cores'] = cores
> > +        return cores
> > +
> > +    def __vm_has_resource(self, vm, resource=''):
> > +        if vm == '':
> > +            self.dut.logger.info("VM name cannt be NULL!!!")
> > +            raise Exception("VM name cannt be NULL!!!")
> 
> How to handle this exception?
> 
> > +        if vm not in self.allocated_info:
> > +            self.dut.logger.info(
> > +                "There is no resource allocated to VM [%s]." % vm)
> > +            return False
> > +        if resource == '':
> > +            return True
> > +        if resource not in self.allocated_info[vm]:
> > +            self.dut.logger.info(
> > +                "There is no resource [%s] allocated to VM [%s] " %
> > +                (resource, vm))
> > +            return False
> > +        return True
> > +
> > +    def free_cpu(self, vm):
> > +        if self.__vm_has_resource(vm, 'cores'):
> > +            for core in self.allocated_info[vm]['cores']:
> > +                self.__core_unused(core)
> > +            self.allocated_info[vm].pop('cores')
> > +
> > +    def alloc_pf(self, vm='', number=-1, socket=-1, pflist=[]):
> > +        """
> > +        There're two options for request pf devices for vm.
> > +        If number is not -1, just allocate pf device from not used
> pfs.
> > +        If list is not None, will allocate pf devices after checked.
> > +        """
> > +        ports = []
> > +
> > +        if number != -1:
> > +            for pci in self.unused_ports:
> > +                if pci != 'unused' and number != 0:
> > +                    if self.__port_on_socket(pci, socket) is True:
> > +                        self.__port_used(pci)
> > +                        ports.append(pci)
> > +                        number = number - 1
> > +            if number != 0:
> > +                print "Can't allocated requested PF devices!!!"
> > +
> Should free used ports and return error.
> 
> > +        if pflist is not None:
> > +            for pci in pflist:
> > +                if self.__port_isused(pci) is True:
> > +                    print "Port %s has been used!!!" % pci
> 
> Should return error.
> > +                else:
> > +                    if self.__port_on_socket(pci, socket) is True:
> > +                        self.__port_used(core)
> > +                        ports.append(core)
> > +
> > +        if vm not in self.allocated_info:
> > +            self.allocated_info[vm] = {}
> > +
> > +        self.allocated_info[vm]['ports'] = ports
> > +        return ports
> > +
> > +    def free_pf(self, vm):
> > +        if self.__vm_has_resource(vm, 'ports'):
> > +            for pci in self.allocated_info[vm]['ports']:
> > +                self.__port_unused(pci)
> > +            self.allocated_info[vm].pop('ports')
> > +
> > +    def alloc_vf_from_pf(self, vm='', pf_pci='', number=-1,
> vflist=[]):
> > +        """
> > +        There're two options for request vf devices of pf device.
> > +        If number is not -1, just allocate vf device from not used
> vfs.
> > +        If list is not None, will allocate vf devices after checked.
> > +        """
> > +        vfs = []
> > +        if vm == '':
> > +            print "Alloc VF request vitual machine name!!!"
> > +            return vfs
> > +
> > +        if pf_pci == '':
> > +            print "Alloc VF request PF pci address!!!"
> > +            return vfs
> > +
> > +        for vf_info in self.vfs_info:
> > +            if vf_info['pf_pci'] == pf_pci:
> > +                if vf_info['pci'] in vflist:
> > +                    vfs.append(vf_info['pci'])
> > +                    continue
> > +
> > +                if number > 0:
> > +                    vfs.append(vf_info['pci'])
> > +                    number = number - 1
> > +
> > +        for vf in vfs:
> > +            self.__vf_used(vf)
> > +
> > +        if vm not in self.allocated_info:
> > +            self.allocated_info[vm] = {}
> > +
> > +        self.allocated_info[vm]['vfs'] = vfs
> > +        return vfs
> > +
> > +    def free_vf(self, vm):
> > +        if self.__vm_has_resource(vm, 'vfs'):
> > +            for pci in self.allocated_info[vm]['vfs']:
> > +                self.__vf_unused(pci)
> > +            self.allocated_info[vm].pop('vfs')
> > +
> > +    def add_vf_on_pf(self, pf_pci='', vflist=[]):
> > +        """
> > +        Add vf devices generated by specified pf devices.
> > +        """
> > +        # add vfs into vf info list
> > +        vfs = []
> > +        for vf in vflist:
> > +            if vf not in self.vfs:
> > +                self.vfs_info.append({'pci': vf, 'pf_pci': pf_pci})
> > +                vfs.append(vf)
> > +        used_vfs = ['unused'] * len(vflist)
> > +        self.unused_vfs += vfs
> > +        self.used_vfs += used_vfs
> > +        self.vfs += vfs
> > +
> > +    def del_vf_on_pf(self, pf_pci='', vflist=[]):
> > +        """
> > +        Remove vf devices generated by specified pf devices.
> > +        """
> > +        vfs = []
> > +        for vf in vflist:
> > +            for vfs_info in self.vfs_info:
> > +                if vfs_info['pci'] == vf:
> > +                    vfs.append(vf)
> > +
> > +        for vf in vfs:
> > +            try:
> > +                index = self.vfs.index(vf)
> > +            except:
> > +                continue
> > +            del self.vfs_info[index]
> > +            del self.unused_vfs[index]
> > +            del self.used_vfs[index]
> > +            del self.vfs[index]
> > +
> > +    def alloc_port(self, vm=''):
> > +        """
> > +        Allocate unused host port for vm
> > +        """
> > +        if vm == '':
> > +            print "Alloc host port request vitual machine name!!!"
> > +            return None
> > +
> > +        port_start = INIT_FREE_PORT + randint(1, 100)
> > +        port_step = randint(1, 10)
> > +        port = None
> > +        count = 20
> > +        while True:
> > +            if self.dut.check_port_occupied(port_start) is False:
> > +                port = port_start
> > +                break
> > +            count -= 1
> > +            if count < 0:
> > +                print 'No available port on the host!!!'
> > +                break
> > +            port_start += port_step
> > +
> > +        if vm not in self.allocated_info:
> > +            self.allocated_info[vm] = {}
> > +
> > +        self.allocated_info[vm]['hostport'] = port
> > +        return port
> > +
> > +    def free_port(self, vm):
> > +        if self.__vm_has_resource(vm, 'hostport'):
> > +            self.allocated_info[vm].pop('hostport')
> > +
> > +    def alloc_vnc_num(self, vm=''):
> > +        """
> > +        Allocate unused host VNC display number for VM.
> > +        """
> > +        if vm == '':
> > +            print "Alloc vnc display number request vitual machine
> > name!!!"
> > +            return None
> > +
> > +        max_vnc_display_num = self.dut.get_maximal_vnc_num()
> > +        free_vnc_display_num = max_vnc_display_num + 1
> > +
> > +        if vm not in self.allocated_info:
> > +            self.allocated_info[vm] = {}
> > +
> > +        self.allocated_info[vm]['vnc_display_num'] =
> free_vnc_display_num
> > +
> > +        return free_vnc_display_num
> > +
> > +    def free_vnc_num(self, vm):
> > +        if self.__vm_has_resource(vm, 'vnc_display_num'):
> > +            self.allocated_info[vm].pop('vnc_display_num')
> > +
> > +    def free_all_resource(self, vm):
> > +        all_free_funcs = get_obj_funcs(self, r'free_')
> > +        for func in all_free_funcs:
> > +            if func.__name__ == 'free_all_resource':
> > +                continue
> > +            func(vm)
> > +        if self.__vm_has_resource(vm):
> > +            self.allocated_info.pop(vm)
> > +
> > +    def get_cpu_on_vm(self, vm=''):
> > +        """
> > +        Return core list on specifid VM.
> > +        """
> > +        if vm in self.allocated_info:
> > +            if "cores" in self.allocated_info[vm]:
> > +                return self.allocated_info[vm]['cores']
> > +
> So many duplicated codes in get_?_on_vm functions, should use simple
> function replace of them.
> 
> > +    def get_vfs_on_vm(self, vm=''):
> > +        """
> > +        Return vf device list on specifid VM.
> > +        """
> > +        if vm in self.allocated_info:
> > +            if 'vfs' in self.allocated_info[vm]:
> > +                return self.allocated_info[vm]['vfs']
> > +
> > +    def get_pfs_on_vm(self, vm=''):
> > +        """
> > +        Return pf device list on specifid VM.
> > +        """
> > +        if vm in self.allocated_info:
> > +            if 'ports' in self.allocated_info[vm]:
> > +                return self.allocated_info[vm]['ports']
> > +
> > +
> > +class simple_dut(object):
> > +
> > +    def __init__(self):
> > +        self.ports_info = []
> > +        self.cores = []
> > +
> > +    def check_port_occupied(self, port):
> > +        return False
> > +
> > +if __name__ == "__main__":
> > +    dut = simple_dut()
> > +    dut.cores = [{'thread': '1', 'socket': '0'}, {'thread': '2',
> 'socket':
> > '0'},
> > +                 {'thread': '3', 'socket': '0'}, {'thread': '4',
> 'socket':
> > '0'},
> > +                 {'thread': '5', 'socket': '0'}, {'thread': '6',
> 'socket':
> > '0'},
> > +                 {'thread': '7', 'socket': '1'}, {'thread': '8',
> 'socket':
> > '1'},
> > +                 {'thread': '9', 'socket': '1'}, {'thread': '10',
> > 'socket': '1'},
> > +                 {'thread': '11', 'socket': '1'}, {'thread': '12',
> > 'socket': '1'}]
> > +
> > +    dut.ports_info = [{'intf': 'p786p1', 'source': 'cfg', 'mac':
> > '90:e2:ba:69:e5:e4',
> > +                       'pci': '08:00.0', 'numa': 0, 'ipv6':
> > 'fe80::92e2:baff:fe69:e5e4',
> > +                       'peer': 'IXIA:6.5', 'type': '8086:10fb'},
> > +                      {'intf': 'p786p2', 'source': 'cfg', 'mac':
> > '90:e2:ba:69:e5:e5',
> > +                       'pci': '08:00.1', 'numa': 0, 'ipv6':
> > 'fe80::92e2:baff:fe69:e5e5',
> > +                       'peer': 'IXIA:6.6', 'type': '8086:10fb'},
> > +                      {'intf': 'p787p1', 'source': 'cfg', 'mac':
> > '90:e2:ba:69:e5:e6',
> > +                       'pci': '84:00.0', 'numa': 1, 'ipv6':
> > 'fe80::92e2:baff:fe69:e5e6',
> > +                       'peer': 'IXIA:6.7', 'type': '8086:10fb'},
> > +                      {'intf': 'p787p2', 'source': 'cfg', 'mac':
> > '90:e2:ba:69:e5:e7',
> > +                       'pci': '84:00.1', 'numa': 1, 'ipv6':
> > 'fe80::92e2:baff:fe69:e5e7',
> > +                       'peer': 'IXIA:6.8', 'type': '8086:10fb'}]
> > +
> > +    virt_pool = VirtResource(dut)
> > +    print "Alloc two PF devices on socket 1 from VM"
> > +    print virt_pool.alloc_pf(vm='test1', number=2, socket=1)
> > +
> > +    virt_pool.add_vf_on_pf(pf_pci='08:00.0', vflist=[
> > +                           '08:10.0', '08:10.2', '08:10.4',
> '08:10.6'])
> > +    virt_pool.add_vf_on_pf(pf_pci='08:00.1', vflist=[
> > +                           '08:10.1', '08:10.3', '08:10.5',
> '08:10.7'])
> > +    print "Add VF devices to resource pool"
> > +    print virt_pool.vfs_info
> > +
> > +    print "Alloc VF device from resource pool"
> > +    print virt_pool.alloc_vf_from_pf(vm='test1', pf_pci='08:00.0',
> > number=2)
> > +    print virt_pool.used_vfs
> > +    print "Alloc VF device from resource pool"
> > +    print virt_pool.alloc_vf_from_pf(vm='test2', pf_pci='08:00.1',
> > vflist=['08:10.3', '08:10.5'])
> > +    print virt_pool.used_vfs
> > +
> > +    print "Del VF devices from resource pool"
> > +    virt_pool.del_vf_on_pf(pf_pci='08:00.0', vflist=['08:10.4',
> > '08:10.2'])
> > +    print virt_pool.vfs_info
> > +
> > +    virt_pool.reserve_cpu('e')
> > +    print "Reserve three cores from resource pool"
> > +    print virt_pool.unused_cores
> > +    print "Alloc two cores on socket1 for VM-test1"
> > +    print virt_pool.alloc_cpu(vm="test1", number=2, socket=1)
> > +    print "Alloc two cores in list for VM-test2"
> > +    print virt_pool.alloc_cpu(vm="test2", corelist=['4', '5'])
> > +    print "Alloc two cores for VM-test3"
> > +    print virt_pool.alloc_cpu(vm="test3", number=2)
> > +    print "Alloc port for VM-test1"
> > +    print virt_pool.alloc_port(vm='test1')
> > +    print "Alloc information after allcated"
> > +    print virt_pool.allocated_info
> > +
> > +    print "Get cores on VM-test1"
> > +    print virt_pool.get_cpu_on_vm("test1")
> > +    print "Get pfs on VM-test1"
> > +    print virt_pool.get_pfs_on_vm("test1")
> > +    print "Get vfs on VM-test2"
> > +    print virt_pool.get_vfs_on_vm("test2")
> > --
> > 1.9.0



More information about the dts mailing list