get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/109307/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 109307,
    "url": "http://patches.dpdk.org/api/patches/109307/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20220406151903.2916254-9-juraj.linkes@pantheon.tech/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20220406151903.2916254-9-juraj.linkes@pantheon.tech>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20220406151903.2916254-9-juraj.linkes@pantheon.tech",
    "date": "2022-04-06T15:18:48",
    "name": "[RFC,v1,08/23] dts: merge DTS framework/virt_base.py to DPDK",
    "commit_ref": null,
    "pull_url": null,
    "state": "rfc",
    "archived": true,
    "hash": "786d144747ae65c06e39b6e50b5be0268d6d0fb9",
    "submitter": {
        "id": 1626,
        "url": "http://patches.dpdk.org/api/people/1626/?format=api",
        "name": "Juraj Linkeš",
        "email": "juraj.linkes@pantheon.tech"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20220406151903.2916254-9-juraj.linkes@pantheon.tech/mbox/",
    "series": [
        {
            "id": 22381,
            "url": "http://patches.dpdk.org/api/series/22381/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=22381",
            "date": "2022-04-06T15:18:40",
            "name": "merge DTS test resource files to DPDK",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/22381/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/109307/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/109307/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 3BEB7A0509;\n\tWed,  6 Apr 2022 17:20:11 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 59E2D42917;\n\tWed,  6 Apr 2022 17:19:19 +0200 (CEST)",
            "from lb.pantheon.sk (lb.pantheon.sk [46.229.239.20])\n by mails.dpdk.org (Postfix) with ESMTP id 1DAD8428B6\n for <dev@dpdk.org>; Wed,  6 Apr 2022 17:19:17 +0200 (CEST)",
            "from localhost (localhost [127.0.0.1])\n by lb.pantheon.sk (Postfix) with ESMTP id 0AA7A19E0DF;\n Wed,  6 Apr 2022 17:19:15 +0200 (CEST)",
            "from lb.pantheon.sk ([127.0.0.1])\n by localhost (lb.pantheon.sk [127.0.0.1]) (amavisd-new, port 10024)\n with ESMTP id ld7D3pmXFANC; Wed,  6 Apr 2022 17:19:14 +0200 (CEST)",
            "from entguard.lab.pantheon.local (unknown [46.229.239.141])\n by lb.pantheon.sk (Postfix) with ESMTP id A5735184FEE;\n Wed,  6 Apr 2022 17:19:08 +0200 (CEST)"
        ],
        "X-Virus-Scanned": "amavisd-new at siecit.sk",
        "From": "=?utf-8?q?Juraj_Linke=C5=A1?= <juraj.linkes@pantheon.tech>",
        "To": "thomas@monjalon.net, david.marchand@redhat.com,\n Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu, lijuan.tu@intel.com",
        "Cc": "dev@dpdk.org, =?utf-8?q?Juraj_Linke=C5=A1?= <juraj.linkes@pantheon.tech>",
        "Subject": "[RFC PATCH v1 08/23] dts: merge DTS framework/virt_base.py to DPDK",
        "Date": "Wed,  6 Apr 2022 15:18:48 +0000",
        "Message-Id": "<20220406151903.2916254-9-juraj.linkes@pantheon.tech>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20220406151903.2916254-1-juraj.linkes@pantheon.tech>",
        "References": "<20220406151903.2916254-1-juraj.linkes@pantheon.tech>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "---\n dts/framework/virt_base.py | 553 +++++++++++++++++++++++++++++++++++++\n 1 file changed, 553 insertions(+)\n create mode 100644 dts/framework/virt_base.py",
    "diff": "diff --git a/dts/framework/virt_base.py b/dts/framework/virt_base.py\nnew file mode 100644\nindex 0000000000..d4af8b985f\n--- /dev/null\n+++ b/dts/framework/virt_base.py\n@@ -0,0 +1,553 @@\n+# BSD LICENSE\n+#\n+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+# All rights reserved.\n+#\n+# Redistribution and use in source and binary forms, with or without\n+# modification, are permitted provided that the following conditions\n+# are met:\n+#\n+#   * Redistributions of source code must retain the above copyright\n+#     notice, this list of conditions and the following disclaimer.\n+#   * Redistributions in binary form must reproduce the above copyright\n+#     notice, this list of conditions and the following disclaimer in\n+#     the documentation and/or other materials provided with the\n+#     distribution.\n+#   * Neither the name of Intel Corporation nor the names of its\n+#     contributors may be used to endorse or promote products derived\n+#     from this software without specific prior written permission.\n+#\n+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+import os\n+import sys\n+import threading\n+import traceback\n+from random import randint\n+\n+import framework.exception as exception\n+import framework.utils as utils\n+\n+from .config import VIRTCONF, VirtConf\n+from .dut import Dut\n+from .logger import getLogger\n+from .settings import CONFIG_ROOT_PATH\n+from .virt_dut import VirtDut\n+\n+ST_NOTSTART = \"NOTSTART\"\n+ST_PAUSE = \"PAUSE\"\n+ST_RUNNING = \"RUNNING\"\n+ST_UNKNOWN = \"UNKNOWN\"\n+VM_IMG_LIST = []\n+mutex_vm_list = threading.Lock()\n+\n+\n+class VirtBase(object):\n+    \"\"\"\n+    Basic module for customer special virtual type. This module implement\n+    functions configured and composed in the VM boot command. With these\n+    function, we can get and set the VM boot command, and instantiate the VM.\n+    \"\"\"\n+\n+    def __init__(self, dut, vm_name, suite_name):\n+        \"\"\"\n+        Initialize the VirtBase.\n+        dut: the instance of Dut\n+        vm_name: the name of VM which you have configured in the configure\n+        suite_name: the name of test suite\n+        \"\"\"\n+        self.host_dut = dut\n+        self.vm_name = vm_name\n+        self.suite = suite_name\n+        # indicate whether the current vm is migration vm\n+        self.migration_vm = False\n+\n+        # create self used host session, need close it later\n+        self.host_session = self.host_dut.new_session(self.vm_name)\n+\n+        self.host_logger = self.host_dut.logger\n+        # base_dir existed for host dut has prepared it\n+        self.host_session.send_expect(\"cd %s\" % self.host_dut.base_dir, \"# \")\n+\n+        # init the host resource pool for VM\n+        self.virt_pool = self.host_dut.virt_pool\n+\n+        if not self.has_virtual_ability():\n+            if not self.enable_virtual_ability():\n+                raise Exception(\"Dut [ %s ] cannot have the virtual ability!!!\")\n+\n+        self.virt_type = self.get_virt_type()\n+\n+        self.params = []\n+        self.local_conf = []\n+\n+        # default call back function is None\n+        self.callback = None\n+\n+        # vm status is running by default, only be changed in internal module\n+        self.vm_status = ST_RUNNING\n+\n+        # by default no special kernel module is required\n+        self.def_driver = \"\"\n+        self.driver_mode = \"\"\n+\n+    def get_virt_type(self):\n+        \"\"\"\n+        Get the virtual type, such as KVM, XEN or LIBVIRT.\n+        \"\"\"\n+        raise NotImplementedError\n+\n+    def has_virtual_ability(self):\n+        \"\"\"\n+        Check if the host have the ability of virtualization.\n+        \"\"\"\n+        NotImplemented\n+\n+    def enable_virtual_ability(self):\n+        \"\"\"\n+        Enable the virtual ability on the DUT.\n+        \"\"\"\n+        NotImplemented\n+\n+    def get_vm_login(self):\n+        \"\"\"\n+        Get VM credentials.\n+        \"\"\"\n+        raise NotImplementedError\n+\n+    def add_vm_login(self):\n+        \"\"\"\n+        Add VM credentials.\n+        \"\"\"\n+        raise NotImplementedError\n+\n+    def _attach_vm(self):\n+        \"\"\"\n+        Attach VM.\n+        \"\"\"\n+        raise NotImplementedError\n+\n+    def _quick_start_vm(self):\n+        \"\"\"\n+        Quick start VM.\n+        \"\"\"\n+        raise NotImplementedError\n+\n+    def load_global_config(self):\n+        \"\"\"\n+        Load global configure in the path CONFIG_ROOT_PATH.\n+        \"\"\"\n+        conf = VirtConf(VIRTCONF)\n+        conf.load_virt_config(self.virt_type)\n+        global_conf = conf.get_virt_config()\n+        for param in global_conf:\n+            for key in list(param.keys()):\n+                if self.find_option_index(key) is None:\n+                    self.__save_local_config(key, param[key])\n+\n+    def set_local_config(self, local_conf):\n+        \"\"\"\n+        Configure VM configuration from user input\n+        \"\"\"\n+        self.local_conf = local_conf\n+\n+    def load_local_config(self, suite_name):\n+        \"\"\"\n+        Load local configure in the path CONFIG_ROOT_PATH ('DTS_ROOT_PATH/$DTS_CFG_FOLDER/' by default).\n+        \"\"\"\n+        # load local configuration by suite and vm name\n+        try:\n+            conf = VirtConf(CONFIG_ROOT_PATH + os.sep + suite_name + \".cfg\")\n+            conf.load_virt_config(self.vm_name)\n+            self.local_conf = conf.get_virt_config()\n+        except:\n+            # when met exception in load VM config\n+            # just leave local conf untouched\n+            pass\n+\n+        # replace global configurations with local configurations\n+        for param in self.local_conf:\n+            if \"virt_type\" in list(param.keys()):\n+                # param 'virt_type' is for virt_base only\n+                continue\n+            # save local configurations\n+            for key in list(param.keys()):\n+                self.__save_local_config(key, param[key])\n+\n+    def __save_local_config(self, key, value):\n+        \"\"\"\n+        Save the local config into the global dict self.param.\n+        \"\"\"\n+        for param in self.params:\n+            if key in list(param.keys()):\n+                param[key] = value\n+                return\n+\n+        self.params.append({key: value})\n+\n+    def compose_boot_param(self):\n+        \"\"\"\n+        Compose all boot param for starting the VM.\n+        \"\"\"\n+        for param in self.params:\n+            key = list(param.keys())[0]\n+            value = param[key]\n+            try:\n+                param_func = getattr(self, \"add_vm_\" + key)\n+                if callable(param_func):\n+                    if type(value) is list:\n+                        for option in value:\n+                            param_func(**option)\n+                else:\n+                    print(utils.RED(\"Virt %s function not callable!!!\" % key))\n+            except AttributeError:\n+                self.host_logger.error(traceback.print_exception(*sys.exc_info()))\n+                print(utils.RED(\"Virt %s function not implemented!!!\" % key))\n+            except Exception:\n+                self.host_logger.error(traceback.print_exception(*sys.exc_info()))\n+                raise exception.VirtConfigParamException(key)\n+\n+    def add_vm_def_driver(self, **options):\n+        \"\"\"\n+        Set default driver which may required when setup VM\n+        \"\"\"\n+        if \"driver_name\" in list(options.keys()):\n+            self.def_driver = options[\"driver_name\"]\n+        if \"driver_mode\" in list(options.keys()):\n+            self.driver_mode = options[\"driver_mode\"]\n+\n+    def find_option_index(self, option):\n+        \"\"\"\n+        Find the boot option in the params which is generated from\n+        the global and local configures, and this function will\n+        return the index by which option can be indexed in the\n+        param list.\n+        \"\"\"\n+        index = 0\n+        for param in self.params:\n+            key = list(param.keys())[0]\n+            if key.strip() == option.strip():\n+                return index\n+            index += 1\n+\n+        return None\n+\n+    def generate_unique_mac(self):\n+        \"\"\"\n+        Generate a unique MAC based on the DUT.\n+        \"\"\"\n+        mac_head = \"00:00:00:\"\n+        mac_tail = \":\".join(\n+            [\"%02x\" % x for x in map(lambda x: randint(0, 255), list(range(3)))]\n+        )\n+        return mac_head + mac_tail\n+\n+    def get_vm_ip(self):\n+        \"\"\"\n+        Get the VM IP.\n+        \"\"\"\n+        raise NotImplementedError\n+\n+    def get_pci_mappings(self):\n+        \"\"\"\n+        Get host and VM pass-through device mapping\n+        \"\"\"\n+        NotImplemented\n+\n+    def isalive(self):\n+        \"\"\"\n+        Check whether VM existed.\n+        \"\"\"\n+        vm_status = self.host_session.send_expect(\n+            \"ps aux | grep qemu | grep 'name %s '| grep -v grep\" % self.vm_name, \"# \"\n+        )\n+\n+        if self.vm_name in vm_status:\n+            return True\n+        else:\n+            return False\n+\n+    def load_config(self):\n+        \"\"\"\n+        Load configurations for VM\n+        \"\"\"\n+        # load global and suite configuration file\n+        self.load_global_config()\n+        self.load_local_config(self.suite)\n+\n+    def attach(self):\n+        # load configuration\n+        self.load_config()\n+\n+        # change login user/password\n+        index = self.find_option_index(\"login\")\n+        if index:\n+            value = self.params[index][\"login\"]\n+            for option in value:\n+                self.add_vm_login(**option)\n+\n+        # attach real vm\n+        self._attach_vm()\n+        return None\n+\n+    def start(self, load_config=True, set_target=True, cpu_topo=\"\", bind_dev=True):\n+        \"\"\"\n+        Start VM and instantiate the VM with VirtDut.\n+        \"\"\"\n+        try:\n+            if load_config is True:\n+                self.load_config()\n+            # compose boot command for different hypervisors\n+            self.compose_boot_param()\n+\n+            # start virtual machine\n+            self._start_vm()\n+\n+            if self.vm_status is ST_RUNNING:\n+                # connect vm dut and init running environment\n+                vm_dut = self.instantiate_vm_dut(\n+                    set_target, cpu_topo, bind_dev=bind_dev, autodetect_topo=True\n+                )\n+            else:\n+                vm_dut = None\n+\n+        except Exception as vm_except:\n+            if self.handle_exception(vm_except):\n+                print(utils.RED(\"Handled exception \" + str(type(vm_except))))\n+            else:\n+                print(utils.RED(\"Unhandled exception \" + str(type(vm_except))))\n+\n+            if callable(self.callback):\n+                self.callback()\n+\n+            return None\n+        return vm_dut\n+\n+    def quick_start(self, load_config=True, set_target=True, cpu_topo=\"\"):\n+        \"\"\"\n+        Only Start VM and not do anything else, will be helpful in multiple VMs\n+        \"\"\"\n+        try:\n+            if load_config is True:\n+                self.load_config()\n+            # compose boot command for different hypervisors\n+            self.compose_boot_param()\n+\n+            # start virtual machine\n+            self._quick_start_vm()\n+\n+        except Exception as vm_except:\n+            if self.handle_exception(vm_except):\n+                print(utils.RED(\"Handled exception \" + str(type(vm_except))))\n+            else:\n+                print(utils.RED(\"Unhandled exception \" + str(type(vm_except))))\n+\n+            if callable(self.callback):\n+                self.callback()\n+\n+    def migrated_start(self, set_target=True, cpu_topo=\"\"):\n+        \"\"\"\n+        Instantiate the VM after migration done\n+        There's no need to load param and start VM because VM has been started\n+        \"\"\"\n+        try:\n+            if self.vm_status is ST_PAUSE:\n+                # flag current vm is migration vm\n+                self.migration_vm = True\n+                # connect backup vm dut and it just inherited from host\n+                vm_dut = self.instantiate_vm_dut(\n+                    set_target, cpu_topo, bind_dev=False, autodetect_topo=False\n+                )\n+        except Exception as vm_except:\n+            if self.handle_exception(vm_except):\n+                print(utils.RED(\"Handled exception \" + str(type(vm_except))))\n+            else:\n+                print(utils.RED(\"Unhandled exception \" + str(type(vm_except))))\n+\n+            return None\n+\n+        return vm_dut\n+\n+    def handle_exception(self, vm_except):\n+        # show exception back trace\n+        exc_type, exc_value, exc_traceback = sys.exc_info()\n+        traceback.print_exception(\n+            exc_type, exc_value, exc_traceback, limit=2, file=sys.stdout\n+        )\n+        if type(vm_except) is exception.ConfigParseException:\n+            # nothing to handle just return True\n+            return True\n+        elif type(vm_except) is exception.VirtConfigParseException:\n+            # nothing to handle just return True\n+            return True\n+        elif type(vm_except) is exception.VirtConfigParamException:\n+            # nothing to handle just return True\n+            return True\n+        elif type(vm_except) is exception.StartVMFailedException:\n+            # start vm failure\n+            return True\n+        elif type(vm_except) is exception.VirtDutConnectException:\n+            # need stop vm\n+            self._stop_vm()\n+            return True\n+        elif type(vm_except) is exception.VirtDutInitException:\n+            # need close session\n+            vm_except.vm_dut.close()\n+            # need stop vm\n+            self.stop()\n+            return True\n+        else:\n+            return False\n+\n+    def _start_vm(self):\n+        \"\"\"\n+        Start VM.\n+        \"\"\"\n+        NotImplemented\n+\n+    def _stop_vm(self):\n+        \"\"\"\n+        Stop VM.\n+        \"\"\"\n+        NotImplemented\n+\n+    def get_vm_img(self):\n+        \"\"\"\n+        get current vm img name from params\n+        get format like: 10.67.110.11:TestVhostMultiQueueQemu:/home/img/Ub1604.img\n+        \"\"\"\n+        param_len = len(self.params)\n+        for i in range(param_len):\n+            if \"disk\" in list(self.params[i].keys()):\n+                value = self.params[i][\"disk\"][0]\n+                if \"file\" in list(value.keys()):\n+                    host_ip = self.host_dut.get_ip_address()\n+                    return (\n+                        host_ip\n+                        + \":\"\n+                        + self.host_dut.test_classname\n+                        + \":\"\n+                        + value[\"file\"]\n+                    )\n+        return None\n+\n+    def instantiate_vm_dut(\n+        self, set_target=True, cpu_topo=\"\", bind_dev=True, autodetect_topo=True\n+    ):\n+        \"\"\"\n+        Instantiate the Dut class for VM.\n+        \"\"\"\n+        crb = self.host_dut.crb.copy()\n+        crb[\"bypass core0\"] = False\n+        vm_ip = self.get_vm_ip()\n+        crb[\"IP\"] = vm_ip\n+        crb[\"My IP\"] = vm_ip\n+        username, password = self.get_vm_login()\n+        crb[\"user\"] = username\n+        crb[\"pass\"] = password\n+\n+        serializer = self.host_dut.serializer\n+\n+        try:\n+            vm_dut = VirtDut(\n+                self,\n+                crb,\n+                serializer,\n+                self.virt_type,\n+                self.vm_name,\n+                self.suite,\n+                cpu_topo,\n+                dut_id=self.host_dut.dut_id,\n+            )\n+        except Exception as vm_except:\n+            self.handle_exception(vm_except)\n+            raise exception.VirtDutConnectException\n+            return None\n+\n+        vm_dut.nic_type = \"any\"\n+        vm_dut.tester = self.host_dut.tester\n+        vm_dut.host_dut = self.host_dut\n+        vm_dut.host_session = self.host_session\n+        vm_dut.init_log()\n+        vm_dut.migration_vm = self.migration_vm\n+\n+        read_cache = False\n+        skip_setup = self.host_dut.skip_setup\n+        vm_img = self.get_vm_img()\n+        # if current vm is migration vm, skip compile dpdk\n+        # if VM_IMG_list include the vm_img, it means the vm have complie the dpdk ok, skip it\n+        if self.migration_vm or vm_img in VM_IMG_LIST:\n+            skip_setup = True\n+        base_dir = self.host_dut.base_dir\n+        vm_dut.set_speedup_options(read_cache, skip_setup)\n+\n+        # package and patch should be set before prerequisites\n+        vm_dut.set_package(self.host_dut.package, self.host_dut.patches)\n+\n+        # base_dir should be set before prerequisites\n+        vm_dut.set_directory(base_dir)\n+\n+        try:\n+            # setting up dpdk in vm, must call at last\n+            vm_dut.target = self.host_dut.target\n+            vm_dut.prerequisites(\n+                self.host_dut.package, self.host_dut.patches, autodetect_topo\n+            )\n+            if set_target:\n+                target = self.host_dut.target\n+                vm_dut.set_target(target, bind_dev, self.def_driver, self.driver_mode)\n+        except:\n+            raise exception.VirtDutInitException(vm_dut)\n+            return None\n+\n+        # after prerequisites and set_target, the dpdk compile is ok, add this vm img to list\n+        if vm_img not in VM_IMG_LIST:\n+            mutex_vm_list.acquire()\n+            VM_IMG_LIST.append(vm_img)\n+            mutex_vm_list.release()\n+\n+        self.vm_dut = vm_dut\n+        return vm_dut\n+\n+    def stop(self):\n+        \"\"\"\n+        Stop the VM.\n+        \"\"\"\n+        self._stop_vm()\n+        self.quit()\n+\n+        self.virt_pool.free_all_resource(self.vm_name)\n+\n+    def quit(self):\n+        \"\"\"\n+        Just quit connection to the VM\n+        \"\"\"\n+        if getattr(self, \"host_session\", None):\n+            self.host_session.close()\n+            self.host_session = None\n+\n+        # vm_dut may not init in migration case\n+        if getattr(self, \"vm_dut\", None):\n+            if self.vm_status is ST_RUNNING:\n+                self.vm_dut.close()\n+            else:\n+                # when vm is not running, not close session forcely\n+                self.vm_dut.close(force=True)\n+\n+            self.vm_dut.logger.logger_exit()\n+            self.vm_dut = None\n+\n+    def register_exit_callback(self, callback):\n+        \"\"\"\n+        Call register exit call back function\n+        \"\"\"\n+        self.callback = callback\n",
    "prefixes": [
        "RFC",
        "v1",
        "08/23"
    ]
}