From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by dpdk.org (Postfix) with ESMTP id 4205F5A41 for ; Fri, 22 May 2015 11:04:30 +0200 (CEST) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga101.fm.intel.com with ESMTP; 22 May 2015 02:04:30 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.13,474,1427785200"; d="scan'208";a="575334609" Received: from shvmail01.sh.intel.com ([10.239.29.42]) by orsmga003.jf.intel.com with ESMTP; 22 May 2015 02:04:28 -0700 Received: from shecgisg003.sh.intel.com (shecgisg003.sh.intel.com [10.239.29.90]) by shvmail01.sh.intel.com with ESMTP id t4M94QZi002947; Fri, 22 May 2015 17:04:26 +0800 Received: from shecgisg003.sh.intel.com (localhost [127.0.0.1]) by shecgisg003.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP id t4M94Otv014349; Fri, 22 May 2015 17:04:26 +0800 Received: (from yliu84x@localhost) by shecgisg003.sh.intel.com (8.13.6/8.13.6/Submit) id t4M94Oqj014345; Fri, 22 May 2015 17:04:24 +0800 From: "Jiajia, Sun" To: dts@dpdk.org Date: Fri, 22 May 2015 17:03:57 +0800 Message-Id: <1432285452-14286-5-git-send-email-sunx.jiajia@intel.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1432285452-14286-1-git-send-email-sunx.jiajia@intel.com> References: <1432285452-14286-1-git-send-email-sunx.jiajia@intel.com> Subject: [dts] [PATCH v2 04/19] Add a module to manage the host resource X-BeenThere: dts@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: test suite reviews and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 May 2015 09:04:31 -0000 From: sjiajiax Added module: framework/virt_resource.py Signed-off-by: sjiajiax --- framework/virt_resource.py | 490 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 490 insertions(+) create mode 100644 framework/virt_resource.py diff --git a/framework/virt_resource.py b/framework/virt_resource.py new file mode 100644 index 0000000..ce60751 --- /dev/null +++ b/framework/virt_resource.py @@ -0,0 +1,490 @@ +#!/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) + + 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) + self.used_ports[index] = pci + self.unused_ports[index] = 'used' + + def __port_unused(self, pci): + index = self.ports.index(pci) + 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) + self.used_vfs[index] = pci + self.unused_vfs[index] = 'used' + + def __vf_unused(self, pci): + index = self.vfs.index(pci) + self.used_vfs[index] = 'unused' + self.unused_vfs[index] = pci + + def __core_used(self, core): + core = int(core) + index = self.cores.index(core) + self.used_cores[index] = core + self.unused_cores[index] = -1 + + def __core_unused(self, core): + core = int(core) + index = self.cores.index(core) + 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 + """ + 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: + 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!!!" + + if corelist is not None: + for core in corelist: + if self.__core_isused(int(core)) is True: + print "Core %s has been used!!!" % core + 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!!!") + 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!!!" + + if pflist is not None: + for pci in pflist: + if self.__port_isused(pci) is True: + print "Port %s has been used!!!" % pci + 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): + """ + Free all resource VM has been allocated. + """ + self.free_port(vm) + self.free_vnc_num(vm) + self.free_vf(vm) + self.free_pf(vm) + self.free_cpu(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'] + + 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.3