From patchwork Thu Aug 15 11:36:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wieczorkiewicz, Pawel" X-Patchwork-Id: 11095665 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AF3F61395 for ; Thu, 15 Aug 2019 11:38:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 98A5728895 for ; Thu, 15 Aug 2019 11:38:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 87168288C3; Thu, 15 Aug 2019 11:38:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00,DKIM_ADSP_ALL, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id A4F5328895 for ; Thu, 15 Aug 2019 11:38:33 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hyE43-0007Ex-EL; Thu, 15 Aug 2019 11:37:07 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hyE42-0007En-Q8 for xen-devel@lists.xenproject.org; Thu, 15 Aug 2019 11:37:06 +0000 X-Inumbo-ID: 01cf11b8-bf51-11e9-96f7-bc764e2007e4 Received: from smtp-fw-9102.amazon.com (unknown [207.171.184.29]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 01cf11b8-bf51-11e9-96f7-bc764e2007e4; Thu, 15 Aug 2019 11:37:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1565869026; x=1597405026; h=from:to:cc:subject:date:message-id:mime-version; bh=SQMIp3coPap3CevdcdMgu/6YN+jQBibo8KuHDmWiKUs=; b=LlE/3aSIL96e9uLCUY5n/0+bMxcxnlyFD0pddCu0vLRJtTW/rxDx81Mw i4QY061JkMZL4HD49irr32s/TGFYWGqJnF9FAwhXuNL25y9lsmlbrLl4M AcsM6QyHEnzNR8JbRKKD7td0QO2E4jwoWThlzjZHpJQPOTW7L1vgvJ95M 4=; X-IronPort-AV: E=Sophos;i="5.64,389,1559520000"; d="scan'208";a="694086312" Received: from sea3-co-svc-lb6-vlan3.sea.amazon.com (HELO email-inbound-relay-1d-9ec21598.us-east-1.amazon.com) ([10.47.22.38]) by smtp-border-fw-out-9102.sea19.amazon.com with ESMTP; 15 Aug 2019 11:37:02 +0000 Received: from EX13MTAUEA001.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan3.iad.amazon.com [10.40.159.166]) by email-inbound-relay-1d-9ec21598.us-east-1.amazon.com (Postfix) with ESMTPS id 6B90EA1F9E; Thu, 15 Aug 2019 11:37:01 +0000 (UTC) Received: from EX13D05EUB001.ant.amazon.com (10.43.166.87) by EX13MTAUEA001.ant.amazon.com (10.43.61.243) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Thu, 15 Aug 2019 11:37:00 +0000 Received: from EX13MTAUWA001.ant.amazon.com (10.43.160.58) by EX13D05EUB001.ant.amazon.com (10.43.166.87) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Thu, 15 Aug 2019 11:36:59 +0000 Received: from dev-dsk-wipawel-1a-0c4e6d58.eu-west-1.amazon.com (10.4.134.33) by mail-relay.amazon.com (10.43.160.118) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Thu, 15 Aug 2019 11:36:56 +0000 From: Pawel Wieczorkiewicz To: Date: Thu, 15 Aug 2019 11:36:46 +0000 Message-ID: <20190815113646.12918-1-wipawel@amazon.de> X-Mailer: git-send-email 2.16.5 MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [PATCH livepatch-python 1/1] livepatch: Add python bindings for livepatch operations X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Wei Liu , Ian Jackson , =?utf-8?q?Marek_Marczykowski-G=C3=B3recki?= , mpohlack@amazon.de, wipawel@amazon.de, amazein@amazon.de, xen-devel@lists.xenproject.org Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Extend the XC python bindings library to support also all common livepatch operations and actions. Add the python bindings for the following operations: - status (pyxc_livepatch_status): Requires a payload name as an input. Returns a status dict containing a state string and a return code integer. - action (pyxc_livepatch_action): Requires a payload name and an action id as an input. Timeout and flags are optional parameters. Returns a return code integer. - upload (pyxc_livepatch_upload): Requires a payload name and a module's filename as an input. Returns a return code integer. - list (pyxc_livepatch_list): Takes no parameters. Returns a list of dicts containing each payload's: * name as a string * state as a string * return code as an integer * list of metadata key=value strings Each functions throws an exception error based on the errno value received from its corresponding libxc function call. Signed-off-by: Pawel Wieczorkiewicz Reviewed-by: Martin Mazein Reviewed-by: Andra-Irina Paraschiv Reviewed-by: Leonard Foerster Reviewed-by: Norbert Manthey --- tools/python/xen/lowlevel/xc/xc.c | 273 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 5459d6834d..87e3b8cacc 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -2008,6 +2008,230 @@ static PyObject *pyflask_access(PyObject *self, PyObject *args, return Py_BuildValue("i",ret); } +static PyObject *pyxc_livepatch_status(XcObject *self, + PyObject *args, + PyObject *kwds) +{ + xen_livepatch_status_t status; + PyObject *info_dict = NULL; + char *name; + int rc; + + static char *kwd_list[] = { "name", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "s", kwd_list, &name) ) + goto error; + + rc = xc_livepatch_get(self->xc_handle, name, &status); + if ( rc ) + goto error; + + info_dict = Py_BuildValue( + "{s:i,s:i}", + "state", status.state, + "rc", status.rc); + +error: + return info_dict ?: pyxc_error_to_exception(self->xc_handle); +} + +static PyObject *pyxc_livepatch_action(XcObject *self, + PyObject *args, + PyObject *kwds) +{ + int (*action_func)(xc_interface *xch, char *name, uint32_t timeout, uint64_t flags); + char *name; + unsigned int action; + uint32_t timeout; + uint64_t flags; + int rc; + + static char *kwd_list[] = { "name", "action", "timeout", "flags", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "sI|Ik", kwd_list, + &name, &action, &timeout, &flags) ) + goto error; + + switch (action) + { + case LIVEPATCH_ACTION_UNLOAD: + action_func = xc_livepatch_unload; + break; + case LIVEPATCH_ACTION_REVERT: + action_func = xc_livepatch_revert; + break; + case LIVEPATCH_ACTION_APPLY: + action_func = xc_livepatch_apply; + break; + case LIVEPATCH_ACTION_REPLACE: + action_func = xc_livepatch_replace; + break; + default: + goto error; + } + + rc = action_func(self->xc_handle, name, timeout, flags); + if ( rc ) + goto error; + + return Py_BuildValue("i", rc); +error: + return pyxc_error_to_exception(self->xc_handle); +} + +static PyObject *pyxc_livepatch_upload(XcObject *self, + PyObject *args, + PyObject *kwds) +{ + unsigned char *fbuf = MAP_FAILED; + char *name, *filename; + struct stat buf; + int fd = 0, rc; + ssize_t len; + + static char *kwd_list[] = { "name", "filename", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwd_list, + &name, &filename)) + goto error; + + fd = open(filename, O_RDONLY); + if ( fd < 0 ) + goto error; + + if ( stat(filename, &buf) != 0 ) + goto error; + + len = buf.st_size; + fbuf = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0); + if ( fbuf == MAP_FAILED ) + goto error; + + rc = xc_livepatch_upload(self->xc_handle, name, fbuf, len); + if ( rc ) + goto error; + + if ( munmap(fbuf, len) ) + { + fbuf = MAP_FAILED; + goto error; + } + close(fd); + + return Py_BuildValue("i", rc);; +error: + if ( fbuf != MAP_FAILED ) + munmap(fbuf, len); + if ( fd >= 0 ) + close(fd); + return pyxc_error_to_exception(self->xc_handle); +} + +static PyObject *pyxc_livepatch_list(XcObject *self) +{ + PyObject *list; + unsigned int nr, done, left, i; + xen_livepatch_status_t *info = NULL; + char *name = NULL; + char *metadata = NULL; + uint32_t *len = NULL; + uint32_t *metadata_len = NULL; + uint64_t name_total_size, metadata_total_size; + off_t name_off, metadata_off; + int rc; + + rc = xc_livepatch_list_get_sizes(self->xc_handle, &nr, + &name_total_size, &metadata_total_size); + if ( rc ) + goto error; + + if ( nr == 0 ) + return PyList_New(0); + + rc = ENOMEM; + info = malloc(nr * sizeof(*info)); + if ( !info ) + goto error; + + name = malloc(name_total_size * sizeof(*name)); + if ( !name ) + goto error; + + len = malloc(nr * sizeof(*len)); + if ( !len ) + goto error; + + metadata = malloc(metadata_total_size * sizeof(*metadata)); + if ( !metadata ) + goto error; + + metadata_len = malloc(nr * sizeof(*metadata_len)); + if ( !metadata_len ) + goto error; + + rc = xc_livepatch_list(self->xc_handle, nr, 0, info, + name, len, name_total_size, + metadata, metadata_len, metadata_total_size, + &done, &left); + if ( rc ) + goto error; + + list = PyList_New(0); + name_off = metadata_off = 0; + for ( i = 0; i < done; i++ ) + { + PyObject *info_dict, *metadata_list; + char *name_str, *metadata_str; + + name_str = name + name_off; + metadata_str = metadata + metadata_off; + + metadata_list = PyList_New(0); + for ( char *s = metadata_str; s < metadata_str + metadata_len[i]; s += strlen(s) + 1 ) + { + PyObject *field = Py_BuildValue("s", s); + if ( field == NULL ) + { + Py_DECREF(list); + Py_DECREF(metadata_list); + rc = EFAULT; + goto error; + } + + PyList_Append(metadata_list, field); + Py_DECREF(field); + } + + info_dict = Py_BuildValue( + "{s:s,s:i,s:i,s:N}", + "name", name_str, + "state", info[i].state, + "rc", info[i].rc, + "metadata", metadata_list); + + if ( info_dict == NULL ) + { + Py_DECREF(list); + Py_DECREF(metadata_list); + rc = EFAULT; + goto error; + } + PyList_Append(list, info_dict); + Py_DECREF(info_dict); + + name_off += len[i]; + metadata_off += metadata_len[i]; + } + +error: + free(info); + free(name); + free(len); + free(metadata); + free(metadata_len); + return rc ? pyxc_error_to_exception(self->xc_handle) : list; +} + static PyMethodDef pyxc_methods[] = { { "domain_create", (PyCFunction)pyxc_domain_create, @@ -2584,6 +2808,44 @@ static PyMethodDef pyxc_methods[] = { "Returns: [int]: 0 on all permission granted; -1 if any permissions are \ denied\n" }, + { "livepatch_status", + (PyCFunction)pyxc_livepatch_status, + METH_KEYWORDS, "\n" + "Gets current state and return code for a specified module.\n" + " name [str]: Module name to be used\n" + "Returns: [dict] on success; throwing an exception on error\n" + " state [int]: Module current state: CHECKED or APPLIED\n" + " rc [int]: Return code of last module's operation\n" }, + + { "livepatch_upload", + (PyCFunction)pyxc_livepatch_upload, + METH_KEYWORDS, "\n" + "Uploads a module with specified name from filename.\n" + " name [str]: Module name to be used\n" + " filename [str]: Filename of a module to be uploaded\n" + "Returns: [int] 0 on success; throwing an exception on error\n" }, + + { "livepatch_action", + (PyCFunction)pyxc_livepatch_action, + METH_KEYWORDS, "\n" + "Performs an action (unload, revert, apply or replace) on a specified \ + module.\n" + " name [str]: Module name to be used\n" + " action [uint]: Action enum id\n" + " timeout [uint]: Action scheduled execution timeout\n" + " flags [ulong]: Flags specifying action's extra parameters\n" + "Returns: [int] 0 on success; throwing an exception on error\n" }, + + { "livepatch_list", + (PyCFunction)pyxc_livepatch_list, + METH_NOARGS, "\n" + "List all uploaded livepatch modules with their current state and metadata.\n" + "Returns: [list of dicts] on success; throwing an exception on error\n" + " name [str]: Module name\n" + " state [int]: Module current state: CHECKED or APPLIED\n" + " rc [int]: Return code of last module's operation\n" + " metadata [list]: List of module's metadata 'key=value' strings\n" }, + { NULL, NULL, 0, NULL } }; @@ -2695,6 +2957,17 @@ PyMODINIT_FUNC initxc(void) PyModule_AddIntConstant(m, "XEN_SCHEDULER_CREDIT", XEN_SCHEDULER_CREDIT); PyModule_AddIntConstant(m, "XEN_SCHEDULER_CREDIT2", XEN_SCHEDULER_CREDIT2); + /* Expose livepatch constants to Python */ + PyModule_AddIntConstant(m, "LIVEPATCH_ACTION_UNLOAD", LIVEPATCH_ACTION_UNLOAD); + PyModule_AddIntConstant(m, "LIVEPATCH_ACTION_REVERT", LIVEPATCH_ACTION_REVERT); + PyModule_AddIntConstant(m, "LIVEPATCH_ACTION_APPLY", LIVEPATCH_ACTION_APPLY); + PyModule_AddIntConstant(m, "LIVEPATCH_ACTION_REPLACE", LIVEPATCH_ACTION_REPLACE); + + PyModule_AddIntConstant(m, "LIVEPATCH_ACTION_APPLY_NODEPS", LIVEPATCH_ACTION_APPLY_NODEPS); + + PyModule_AddIntConstant(m, "LIVEPATCH_STATE_APPLIED", LIVEPATCH_STATE_APPLIED); + PyModule_AddIntConstant(m, "LIVEPATCH_STATE_CHECKED", LIVEPATCH_STATE_CHECKED); + #if PY_MAJOR_VERSION >= 3 return m; #endif