get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 1524519,
    "url": "http://patchwork.ozlabs.org/api/patches/1524519/",
    "web_url": "http://patchwork.ozlabs.org/project/ovn/patch/20210903192748.1408062-5-frode.nordahl@canonical.com/",
    "project": {
        "id": 68,
        "url": "http://patchwork.ozlabs.org/api/projects/68/",
        "name": "Open Virtual Network development",
        "link_name": "ovn",
        "list_id": "ovs-dev.openvswitch.org",
        "list_email": "ovs-dev@openvswitch.org",
        "web_url": "http://openvswitch.org/",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20210903192748.1408062-5-frode.nordahl@canonical.com>",
    "list_archive_url": null,
    "date": "2021-09-03T19:27:43",
    "name": "[ovs-dev,v4,4/9] controller: Move OVS port functions to new module.",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "43ccec9cc13b13d00b74ed823d069c4acd124a05",
    "submitter": {
        "id": 77851,
        "url": "http://patchwork.ozlabs.org/api/people/77851/",
        "name": "Frode Nordahl",
        "email": "frode.nordahl@canonical.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/ovn/patch/20210903192748.1408062-5-frode.nordahl@canonical.com/mbox/",
    "series": [
        {
            "id": 260950,
            "url": "http://patchwork.ozlabs.org/api/series/260950/",
            "web_url": "http://patchwork.ozlabs.org/project/ovn/list/?series=260950",
            "date": "2021-09-03T19:27:42",
            "name": "Introduce infrastructure for plugging providers",
            "version": 4,
            "mbox": "http://patchwork.ozlabs.org/series/260950/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1524519/comments/",
    "check": "success",
    "checks": "http://patchwork.ozlabs.org/api/patches/1524519/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<ovs-dev-bounces@openvswitch.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "dev@openvswitch.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "ovs-dev@lists.linuxfoundation.org"
        ],
        "Authentication-Results": [
            "ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=canonical.com header.i=@canonical.com\n header.a=rsa-sha256 header.s=20210705 header.b=NsxBCl+N;\n\tdkim-atps=neutral",
            "ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN>)",
            "smtp3.osuosl.org (amavisd-new);\n dkim=pass (2048-bit key) header.d=canonical.com"
        ],
        "Received": [
            "from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest\n SHA256)\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 4H1SW77558z9sSs\n\tfor <incoming@patchwork.ozlabs.org>; Sat,  4 Sep 2021 05:28:03 +1000 (AEST)",
            "from localhost (localhost [127.0.0.1])\n\tby smtp2.osuosl.org (Postfix) with ESMTP id 0713D40839;\n\tFri,  3 Sep 2021 19:28:01 +0000 (UTC)",
            "from smtp2.osuosl.org ([127.0.0.1])\n\tby localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id WjTM0mKsNIlG; Fri,  3 Sep 2021 19:27:59 +0000 (UTC)",
            "from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])\n\tby smtp2.osuosl.org (Postfix) with ESMTPS id DE2BE4081B;\n\tFri,  3 Sep 2021 19:27:57 +0000 (UTC)",
            "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id C4793C0024;\n\tFri,  3 Sep 2021 19:27:55 +0000 (UTC)",
            "from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 11222C000E\n for <dev@openvswitch.org>; Fri,  3 Sep 2021 19:27:54 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by smtp3.osuosl.org (Postfix) with ESMTP id 0055961584\n for <dev@openvswitch.org>; Fri,  3 Sep 2021 19:27:54 +0000 (UTC)",
            "from smtp3.osuosl.org ([127.0.0.1])\n by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n with ESMTP id pS-Iwt-wbt6d for <dev@openvswitch.org>;\n Fri,  3 Sep 2021 19:27:52 +0000 (UTC)",
            "from smtp-relay-canonical-1.canonical.com\n (smtp-relay-canonical-1.canonical.com [185.125.188.121])\n by smtp3.osuosl.org (Postfix) with ESMTPS id 7D66F61542\n for <dev@openvswitch.org>; Fri,  3 Sep 2021 19:27:52 +0000 (UTC)",
            "from frode-threadripper.. (1.general.frode.uk.vpn [10.172.193.250])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by smtp-relay-canonical-1.canonical.com (Postfix) with ESMTPSA id 5CC13401A7;\n Fri,  3 Sep 2021 19:27:50 +0000 (UTC)"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "domain auto-whitelisted by SQLgrey-1.8.0",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com;\n s=20210705; t=1630697270;\n bh=qDKddMr2hyQXl8C/ogw0w+X+UyAodDsypoaem7LcOPI=;\n h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:\n MIME-Version;\n b=NsxBCl+NBkY20BOIkc7f0gYULExIc9DblwCn5xDdDszjt482hYa3rH3HczaB2q1PY\n RiOjLJWixWqBAJVYbdcY06oHxv3+LRTrsD/axCCpMar/Eg+g8Gppf7RV43oxzJSSWG\n 1fDeUShugLJjpzuvdXzEXXrGasWruhaG+kuq3Gz206kRMKQ6WzYs4Y8yHYWRr0UDhx\n H9XI/lMYLPi5rWv/pEQj//37ae8wUov8n+i/PKo0/9Lx6Z14EzfG28N54M52iZewgg\n chH+Pw3BDm3wtUK+DmnA/fxEhhHtv+uBM2oBMVaJPJZmFLr/4WOjZv6z6j1Vj1wPEZ\n 3rZREfOskaCrQ==",
        "From": "Frode Nordahl <frode.nordahl@canonical.com>",
        "To": "dev@openvswitch.org",
        "Date": "Fri,  3 Sep 2021 21:27:43 +0200",
        "Message-Id": "<20210903192748.1408062-5-frode.nordahl@canonical.com>",
        "X-Mailer": "git-send-email 2.32.0",
        "In-Reply-To": "<20210903192748.1408062-1-frode.nordahl@canonical.com>",
        "References": "<20210903192748.1408062-1-frode.nordahl@canonical.com>",
        "MIME-Version": "1.0",
        "Subject": "[ovs-dev] [PATCH ovn v4 4/9] controller: Move OVS port functions to\n\tnew module.",
        "X-BeenThere": "ovs-dev@openvswitch.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "<ovs-dev.openvswitch.org>",
        "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>",
        "List-Archive": "<http://mail.openvswitch.org/pipermail/ovs-dev/>",
        "List-Post": "<mailto:ovs-dev@openvswitch.org>",
        "List-Help": "<mailto:ovs-dev-request@openvswitch.org?subject=help>",
        "List-Subscribe": "<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "ovs-dev-bounces@openvswitch.org",
        "Sender": "\"dev\" <ovs-dev-bounces@openvswitch.org>"
    },
    "content": "Up until now the controller patch module has been the only\nconsumer of functions to maintain OVS ports and interfaces.\n\nWith the introduction of infrastructure for plugging providers\nthese functions will also be consumed by the controller binding\nmodule.\n\nAs such we introduce a new module called ovsport where these\nshared utility functions can live and be consumed by multiple\nmodules.\n\nSigned-off-by: Frode Nordahl <frode.nordahl@canonical.com>\n---\n controller/automake.mk |   4 +-\n controller/ovsport.c   | 256 +++++++++++++++++++++++++++++++++++++++++\n controller/ovsport.h   |  60 ++++++++++\n 3 files changed, 319 insertions(+), 1 deletion(-)\n create mode 100644 controller/ovsport.c\n create mode 100644 controller/ovsport.h",
    "diff": "diff --git a/controller/automake.mk b/controller/automake.mk\nindex 41f907d6e..ad2d68af2 100644\n--- a/controller/automake.mk\n+++ b/controller/automake.mk\n@@ -35,7 +35,9 @@ controller_ovn_controller_SOURCES = \\\n \tcontroller/mac-learn.c \\\n \tcontroller/mac-learn.h \\\n \tcontroller/local_data.c \\\n-\tcontroller/local_data.h\n+\tcontroller/local_data.h \\\n+\tcontroller/ovsport.h \\\n+\tcontroller/ovsport.c\n \n controller_ovn_controller_LDADD = lib/libovn.la $(OVS_LIBDIR)/libopenvswitch.la\n man_MANS += controller/ovn-controller.8\ndiff --git a/controller/ovsport.c b/controller/ovsport.c\nnew file mode 100644\nindex 000000000..b1183e9ed\n--- /dev/null\n+++ b/controller/ovsport.c\n@@ -0,0 +1,256 @@\n+/* Copyright (c) 2021 Canonical\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at:\n+ *\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+#include <config.h>\n+#include \"ovsport.h\"\n+\n+#include \"lib/vswitch-idl.h\"\n+#include \"openvswitch/vlog.h\"\n+\n+VLOG_DEFINE_THIS_MODULE(ovsport);\n+\n+/* Create a port and interface record and add it to 'bridge' in the Open\n+ * vSwitch database represented by 'ovs_idl_txn'.\n+ *\n+ * 'name' is required and is used both for the name of the port and interface\n+ * records.  Depending on the contents of the optional 'iface_type' parameter\n+ * the name may need to refer to an existing interface in the system.  It is\n+ * the callers responsibility to ensure that no other port with the desired\n+ * name already exist.\n+ *\n+ * 'iface_type' optionally specifies the type of intercace, otherwise set it to\n+ * NULL.\n+ *\n+ * 'port_external_ids' - the contents of the map will be used to fill the\n+ * external_ids column of the created port record, otherwise set it to NULL.\n+ *\n+ * 'iface_external_ids' - the contents of the map will be used to fill the\n+ * external_ids column of the created interface record, otherwise set it to\n+ * NULL.\n+ *\n+ * 'iface_options' - the contents of the map will be used to fill the options\n+ * column of the created interface record, otherwise set it to NULL.\n+ *\n+ * 'iface_mtu_request' - if a value > 0 is provided it will be filled into the\n+ * mtu_request column of the created interface record. */\n+void\n+ovsport_create(struct ovsdb_idl_txn *ovs_idl_txn,\n+               const struct ovsrec_bridge *bridge,\n+               const char *name,\n+               const char *iface_type,\n+               const struct smap *port_external_ids,\n+               const struct smap *iface_external_ids,\n+               const struct smap *iface_options,\n+               const int64_t iface_mtu_request)\n+{\n+    struct ovsrec_interface *iface;\n+    iface = ovsrec_interface_insert(ovs_idl_txn);\n+    ovsrec_interface_set_name(iface, name);\n+    if (iface_type) {\n+        ovsrec_interface_set_type(iface, iface_type);\n+    }\n+    ovsrec_interface_set_external_ids(iface, iface_external_ids);\n+    ovsrec_interface_set_options(iface, iface_options);\n+    ovsrec_interface_set_mtu_request(\n+            iface, &iface_mtu_request, iface_mtu_request > 0);\n+\n+    struct ovsrec_port *port;\n+    port = ovsrec_port_insert(ovs_idl_txn);\n+    ovsrec_port_set_name(port, name);\n+    ovsrec_port_set_interfaces(port, &iface, 1);\n+    ovsrec_port_set_external_ids(port, port_external_ids);\n+\n+    ovsrec_bridge_update_ports_addvalue(bridge, port);\n+    ovsrec_bridge_verify_ports(bridge);\n+}\n+\n+/* Remove 'port' from 'bridge' and delete the 'port' recrd and any records\n+ * with a weakRef to it. */\n+void\n+ovsport_remove(const struct ovsrec_bridge *bridge,\n+               const struct ovsrec_port *port)\n+{\n+    ovsrec_bridge_update_ports_delvalue(bridge, port);\n+    ovsrec_bridge_verify_ports(bridge);\n+    ovsrec_port_delete(port);\n+}\n+\n+static void update_interface_smap_column(\n+        const struct ovsrec_interface *, const struct smap *,\n+        const struct smap *, void (*fsetkey)(const struct ovsrec_interface *,\n+                                             const char *, const char *));\n+static void maintain_interface_smap_column(\n+        const struct ovsrec_interface *, const struct sset *,\n+        const struct smap *, const struct smap *,\n+        void (*fsetkey)(const struct ovsrec_interface *, const char *,\n+                        const char *),\n+        void (*fdelkey)(const struct ovsrec_interface *,\n+                         const char *));\n+\n+/* Update interface record as represented by 'iface'.\n+ *\n+ * 'type' optionally specifies the type of interface, to unset type set to an\n+ * empty string, to not update type set to NULL.\n+ *\n+ * 'external_ids' optionally provide a map of external_ids to update, to not\n+ * update external_ids set to NULL.\n+ *\n+ * 'mnt_external_ids' optionally provide set of 'external_ids' to maintain.\n+ * When set the function will make sure that all keys in the 'mnt_external_ids'\n+ * set have values from the 'external_ids' map in the database.  Every key that\n+ * exist in 'mnt_external_ids' with no corresponding key in 'external_ids' will\n+ * be removed from the database if present.  Set to NULL to not maintain the\n+ * record in this way.\n+ *\n+ * 'options' optionally provide a map of options to update, to not\n+ * update options set to NULL.\n+ *\n+ * 'mnt_options' optionally provide set of 'options' to maintain.\n+ * When set the function will make sure that all keys in the 'mnt_options' set\n+ * have values from the 'options' map in the database.  Every key that exist in\n+ * 'mnt_options' with no corresponding key in 'options' will be\n+ * removed from the database if present.  Set to NULL to not maintain the\n+ * record in this way.\n+ *\n+ * 'iface_mtu_request' - if a value > 0 is provided it will be filled into the\n+ * mtu_request column of the created interface record. */\n+void\n+ovsport_update_iface(const struct ovsrec_interface *iface,\n+                     const char *type,\n+                     const struct smap *external_ids,\n+                     const struct sset *mnt_external_ids,\n+                     const struct smap *options,\n+                     const struct sset *mnt_options,\n+                     const int64_t mtu_request)\n+{\n+    if (type && strcmp(iface->type, type)) {\n+        ovsrec_interface_set_type(iface, type);\n+    }\n+\n+    if (external_ids && mnt_external_ids) {\n+        maintain_interface_smap_column(\n+                iface, mnt_external_ids, external_ids, &iface->external_ids,\n+                ovsrec_interface_update_external_ids_setkey,\n+                ovsrec_interface_update_external_ids_delkey);\n+    } else if (external_ids) {\n+        update_interface_smap_column(\n+                iface, external_ids, &iface->external_ids,\n+                ovsrec_interface_update_external_ids_setkey);\n+    }\n+\n+    if (options && mnt_options) {\n+        maintain_interface_smap_column(\n+                iface, mnt_options, options, &iface->options,\n+                ovsrec_interface_update_options_setkey,\n+                ovsrec_interface_update_options_delkey);\n+    } else if (options) {\n+        update_interface_smap_column(\n+                iface, options, &iface->options,\n+                ovsrec_interface_update_options_setkey);\n+    }\n+\n+    if (mtu_request > 0) {\n+        if ((iface->mtu_request && *iface->mtu_request != mtu_request)\n+            || !iface->mtu_request)\n+        {\n+            ovsrec_interface_set_mtu_request(\n+                    iface, &mtu_request, mtu_request > 0);\n+        }\n+    } else if (iface->mtu_request) {\n+        ovsrec_interface_update_mtu_request_delvalue(iface,\n+                                                     *iface->mtu_request);\n+    }\n+}\n+\n+const struct ovsrec_port *\n+ovsport_lookup_by_interfaces(\n+        struct ovsdb_idl_index *ovsrec_port_by_interfaces,\n+        struct ovsrec_interface **interfaces,\n+        const size_t n_interfaces)\n+{\n+    struct ovsrec_port *port = ovsrec_port_index_init_row(\n+            ovsrec_port_by_interfaces);\n+    ovsrec_port_index_set_interfaces(port, interfaces, n_interfaces);\n+\n+    const struct ovsrec_port *retval = ovsrec_port_index_find(\n+            ovsrec_port_by_interfaces, port);\n+\n+    ovsrec_port_index_destroy_row(port);\n+\n+    return retval;\n+}\n+\n+const struct\n+ovsrec_port * ovsport_lookup_by_interface(\n+        struct ovsdb_idl_index *ovsrec_port_by_interfaces,\n+        struct ovsrec_interface *interface)\n+{\n+    struct ovsrec_interface *interfaces[] = {interface};\n+\n+    return ovsport_lookup_by_interfaces(ovsrec_port_by_interfaces,\n+                                        interfaces, 1);\n+}\n+\n+/* Update an interface map column with the key/value pairs present in the\n+ * provided smap, only applying changes when necessary. */\n+static void\n+update_interface_smap_column(\n+        const struct ovsrec_interface *iface,\n+        const struct smap *smap,\n+        const struct smap *db_smap,\n+        void (*fsetkey)(const struct ovsrec_interface *,\n+                         const char *, const char *))\n+{\n+    struct smap_node *node;\n+\n+    SMAP_FOR_EACH (node, smap) {\n+        const char *db_value = smap_get(db_smap, node->key);\n+\n+        if ((db_value && strcmp(db_value, node->value))\n+            || !db_value)\n+        {\n+            fsetkey(iface, node->key, node->value);\n+        }\n+    }\n+}\n+\n+/* Like update_interface_smap_column, but also takes an sset with all the keys\n+ * we want to maintain.  Any key present in the sset but not in the provided\n+ * smap will be removed from the database if present there. */\n+static void\n+maintain_interface_smap_column(\n+        const struct ovsrec_interface *iface,\n+        const struct sset *mnt_items,\n+        const struct smap *smap,\n+        const struct smap *db_smap,\n+        void (*fsetkey)(const struct ovsrec_interface *,\n+                         const char *, const char *),\n+        void (*fdelkey)(const struct ovsrec_interface *,\n+                         const char *))\n+{\n+    const char *ref_name;\n+\n+    SSET_FOR_EACH (ref_name, mnt_items) {\n+        const char *value = smap_get(smap, ref_name);\n+        const char *db_value = smap_get(db_smap, ref_name);\n+        if (!value && db_value) {\n+            fdelkey(iface, ref_name);\n+        } else if ((db_value && value && strcmp(db_value, value))\n+                   || (value && !db_value))\n+        {\n+            fsetkey(iface, ref_name, value);\n+        }\n+    }\n+}\ndiff --git a/controller/ovsport.h b/controller/ovsport.h\nnew file mode 100644\nindex 000000000..e355ff7ff\n--- /dev/null\n+++ b/controller/ovsport.h\n@@ -0,0 +1,60 @@\n+/* Copyright (c) 2021 Canonical\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at:\n+ *\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+#ifndef OVSPORT_H\n+#define OVSPORT_H 1\n+\n+/* OVS Ports\n+ * =========\n+ *\n+ * This module contains utility functions for adding, removing and maintaining\n+ * ports and their interface records on OVS bridges. */\n+\n+#include \"smap.h\"\n+#include \"sset.h\"\n+\n+#include <stdbool.h>\n+#include <stdint.h>\n+\n+struct ovsdb_idl_txn;\n+struct ovsrec_bridge;\n+struct ovsrec_port;\n+struct ovsrec_interface;\n+struct ovsdb_idl_index;\n+\n+void ovsport_create(struct ovsdb_idl_txn *ovs_idl_txn,\n+                    const struct ovsrec_bridge *bridge,\n+                    const char *name,\n+                    const char *iface_type,\n+                    const struct smap *port_external_ids,\n+                    const struct smap *iface_external_ids,\n+                    const struct smap *iface_options,\n+                    const int64_t iface_mtu_request);\n+void ovsport_remove(const struct ovsrec_bridge *bridge,\n+                    const struct ovsrec_port *port);\n+void ovsport_update_iface(const struct ovsrec_interface *iface,\n+                          const char *type,\n+                          const struct smap *external_ids,\n+                          const struct sset *mnt_external_ids,\n+                          const struct smap *options,\n+                          const struct sset *mnt_options,\n+                          const int64_t mtu_request);\n+const struct ovsrec_port * ovsport_lookup_by_interfaces(\n+        struct ovsdb_idl_index *, struct ovsrec_interface **,\n+        const size_t n_interfaces);\n+const struct ovsrec_port * ovsport_lookup_by_interface(\n+        struct ovsdb_idl_index *, struct ovsrec_interface *);\n+\n+#endif /* lib/ovsport.h */\n",
    "prefixes": [
        "ovs-dev",
        "v4",
        "4/9"
    ]
}