get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 806358,
    "url": "http://patchwork.ozlabs.org/api/patches/806358/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/openvswitch/patch/1503893682-65314-1-git-send-email-zhouhan@gmail.com/",
    "project": {
        "id": 47,
        "url": "http://patchwork.ozlabs.org/api/projects/47/?format=api",
        "name": "Open vSwitch",
        "link_name": "openvswitch",
        "list_id": "ovs-dev.openvswitch.org",
        "list_email": "ovs-dev@openvswitch.org",
        "web_url": "http://openvswitch.org/",
        "scm_url": "git@github.com:openvswitch/ovs.git",
        "webscm_url": "https://github.com/openvswitch/ovs",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1503893682-65314-1-git-send-email-zhouhan@gmail.com>",
    "list_archive_url": null,
    "date": "2017-08-28T04:14:40",
    "name": "[ovs-dev,v4,1/3] ovn-controller: readonly mode binding_run and get_br_int",
    "commit_ref": null,
    "pull_url": null,
    "state": "deferred",
    "archived": false,
    "hash": "5fe767920818b4f6d70db061dc379697122158cc",
    "submitter": {
        "id": 67381,
        "url": "http://patchwork.ozlabs.org/api/people/67381/?format=api",
        "name": "Han Zhou",
        "email": "zhouhan@gmail.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/openvswitch/patch/1503893682-65314-1-git-send-email-zhouhan@gmail.com/mbox/",
    "series": [
        {
            "id": 66,
            "url": "http://patchwork.ozlabs.org/api/series/66/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/openvswitch/list/?series=66",
            "date": "2017-08-28T04:14:40",
            "name": "[ovs-dev,v4,1/3] ovn-controller: readonly mode binding_run and get_br_int",
            "version": 4,
            "mbox": "http://patchwork.ozlabs.org/series/66/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/806358/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/806358/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@mail.linuxfoundation.org"
        ],
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"in5onSlJ\"; dkim-atps=neutral"
        ],
        "Received": [
            "from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xgdj667W8z9sN7\n\tfor <incoming@patchwork.ozlabs.org>;\n\tMon, 28 Aug 2017 14:15:22 +1000 (AEST)",
            "from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id 75BBB899;\n\tMon, 28 Aug 2017 04:15:01 +0000 (UTC)",
            "from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id 0A090516\n\tfor <dev@openvswitch.org>; Mon, 28 Aug 2017 04:15:00 +0000 (UTC)",
            "from mail-pg0-f67.google.com (mail-pg0-f67.google.com\n\t[74.125.83.67])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 0501479\n\tfor <dev@openvswitch.org>; Mon, 28 Aug 2017 04:14:58 +0000 (UTC)",
            "by mail-pg0-f67.google.com with SMTP id t193so2448341pgc.4\n\tfor <dev@openvswitch.org>; Sun, 27 Aug 2017 21:14:58 -0700 (PDT)",
            "from localhost.localdomain.localdomain\n\t(c-73-162-150-77.hsd1.ca.comcast.net. [73.162.150.77])\n\tby smtp.gmail.com with ESMTPSA id\n\tm13sm22022684pfg.27.2017.08.27.21.14.57\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tSun, 27 Aug 2017 21:14:57 -0700 (PDT)"
        ],
        "X-Greylist": "whitelisted by SQLgrey-1.7.6",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=from:to:cc:subject:date:message-id;\n\tbh=t+Fw7yEen0tboF39qi7L5VWcUAQ2qkF3b2K6ok552cI=;\n\tb=in5onSlJHbe0zjmUAJn1gpqWjOuShqlJDHtWa+V8hkpPLMyiHgpLnHabffNOATXZ2C\n\tUMB5QJd9Dzei1+2/rMG6CENCoQd6oLn3kKtTSjIVzqmNn1C0JYYRq50xVqdUnX0o4kYy\n\tW85UrfL0HhHcDNOgxNcFh0Kis9jevXHO4AFwYwrEWQXjJg73wITUITZ1CjnrGjvnTwnT\n\tDKDkpRBA+PuhIS62+nPVSIvlw27bWvDr7dDZRBMMf/tm0eZOuJWjj71U676gTwUqontY\n\tPym/ZQJXv3/jGtER6/gMz0rH8IQsMrE8TGdgI1hCe1h2fKM8B/KLbfjTPVCvsTco66X/\n\twrNQ==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id;\n\tbh=t+Fw7yEen0tboF39qi7L5VWcUAQ2qkF3b2K6ok552cI=;\n\tb=AIR1voD5TxHusuvvgCdad9fZZZOfT5q058vZu1Ec2HaqDQeO76pgZeO2AT49VVDSyY\n\t2foHefMH7roHM0cEGs5DiD+jrcqPyTsSyCbPv3qHfbHU6GKHo1N2EmazOg51GasM6rkI\n\t3XADaaL9d/NX85kelN6q4TtnV7pFgx0e7rPuv8IwZ6aDaiMk8Bt/B51HpUb8ycf3HJB0\n\t+KuLssqm87JApkFQEwEfIY9Nssb0x32a0bUPIU59gL++fmMS33ngXOi4NHUM9ONIWq1N\n\t5PUUZwsih/qmpLE1NDhpiJMzjh3SKSXDdEws7V8qk8NoPjclLOKR6IhPdPkhZ2aUOVqp\n\tv07Q==",
        "X-Gm-Message-State": "AHYfb5ggSUU2CX4Uz+tJtT3smrqTXifnoaa1gizyAq4Tyxz6w6F9Qmuc\n\tTGp3o0qqHouZdQTJ",
        "X-Received": "by 10.98.58.220 with SMTP id v89mr5090477pfj.23.1503893698090;\n\tSun, 27 Aug 2017 21:14:58 -0700 (PDT)",
        "From": "Han Zhou <zhouhan@gmail.com>",
        "To": "dev@openvswitch.org",
        "Date": "Sun, 27 Aug 2017 21:14:40 -0700",
        "Message-Id": "<1503893682-65314-1-git-send-email-zhouhan@gmail.com>",
        "X-Mailer": "git-send-email 2.1.0",
        "X-Spam-Status": "No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,\n\tDKIM_VALID_AU,FREEMAIL_FROM,RCVD_IN_DNSWL_NONE autolearn=disabled\n\tversion=3.3.1",
        "X-Spam-Checker-Version": "SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org",
        "Subject": "[ovs-dev] [PATCH v4 1/3] ovn-controller: readonly mode binding_run\n\tand get_br_int",
        "X-BeenThere": "ovs-dev@openvswitch.org",
        "X-Mailman-Version": "2.1.12",
        "Precedence": "list",
        "List-Id": "<ovs-dev.openvswitch.org>",
        "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<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\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Sender": "ovs-dev-bounces@openvswitch.org",
        "Errors-To": "ovs-dev-bounces@openvswitch.org"
    },
    "content": "This change is to prepare for the future change for multi-threading.\nBoth binding_run() and get_br_int() are needed by pinctrl thread,\nbut we don't want to update SB DB or create bridges in that scenario,\nso need \"readonly\" mode for these functions.\n\nSigned-off-by: Han Zhou <zhouhan@gmail.com>\nCo-authored-by: Ben Pfaff <blp@ovn.org>\n---\nv3->v4: rebased on master.\n\n ovn/controller/binding.c        | 250 ++++++++++++++++++++++++----------------\n ovn/controller/binding.h        |   5 +\n ovn/controller/ovn-controller.c |  30 +++--\n 3 files changed, 172 insertions(+), 113 deletions(-)",
    "diff": "diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c\nindex 6a56e26..bb1728f 100644\n--- a/ovn/controller/binding.c\n+++ b/ovn/controller/binding.c\n@@ -71,36 +71,36 @@ binding_register_ovs_idl(struct ovsdb_idl *ovs_idl)\n static void\n get_local_iface_ids(const struct ovsrec_bridge *br_int,\n                     struct shash *lport_to_iface,\n-                    struct sset *local_lports,\n-                    struct sset *egress_ifaces)\n+                    struct sset *local_lports)\n {\n-    int i;\n-\n-    for (i = 0; i < br_int->n_ports; i++) {\n-        const struct ovsrec_port *port_rec = br_int->ports[i];\n-        const char *iface_id;\n-        int j;\n-\n-        if (!strcmp(port_rec->name, br_int->name)) {\n-            continue;\n-        }\n-\n-        for (j = 0; j < port_rec->n_interfaces; j++) {\n-            const struct ovsrec_interface *iface_rec;\n-\n-            iface_rec = port_rec->interfaces[j];\n-            iface_id = smap_get(&iface_rec->external_ids, \"iface-id\");\n-            int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : 0;\n+    for (int i = 0; i < br_int->n_ports; i++) {\n+        const struct ovsrec_port *port = br_int->ports[i];\n+        for (int j = 0; j < port->n_interfaces; j++) {\n+            const struct ovsrec_interface *iface\n+                = port->interfaces[j];\n+            const char *iface_id = smap_get(&iface->external_ids, \"iface-id\");\n+            int64_t ofport = iface->n_ofport ? *iface->ofport : 0;\n \n             if (iface_id && ofport > 0) {\n-                shash_add(lport_to_iface, iface_id, iface_rec);\n+                shash_add(lport_to_iface, iface_id, iface);\n                 sset_add(local_lports, iface_id);\n             }\n+        }\n+    }\n+}\n+\n+static void\n+get_egress_ifaces(const struct ovsrec_bridge *br_int,\n+                  struct sset *egress_ifaces)\n+{\n+    for (int i = 0; i < br_int->n_ports; i++) {\n+        const struct ovsrec_port *port = br_int->ports[i];\n+        for (int j = 0; j < port->n_interfaces; j++) {\n+            const struct ovsrec_interface *iface = port->interfaces[j];\n \n-            /* Check if this is a tunnel interface. */\n-            if (smap_get(&iface_rec->options, \"remote_ip\")) {\n+            if (smap_get(&iface->options, \"remote_ip\")) {\n                 const char *tunnel_iface\n-                    = smap_get(&iface_rec->status, \"tunnel_egress_iface\");\n+                    = smap_get(&iface->status, \"tunnel_egress_iface\");\n                 if (tunnel_iface) {\n                     sset_add(egress_ifaces, tunnel_iface);\n                 }\n@@ -370,7 +370,9 @@ setup_qos(const char *egress_iface, struct hmap *queue_map)\n     netdev_close(netdev_phy);\n }\n \n-static void\n+/* Returns true if this chassis owns 'binding_rec', that is, it should set\n+ * 'binding_rec->chassis' to point to 'chassis_rec'. */\n+static bool\n consider_local_datapath(struct controller_ctx *ctx,\n                         const struct chassis_index *chassis_index,\n                         struct sset *active_tunnels,\n@@ -385,7 +387,6 @@ consider_local_datapath(struct controller_ctx *ctx,\n         = shash_find_data(lport_to_iface, binding_rec->logical_port);\n     struct ovs_list *gateway_chassis = NULL;\n \n-    bool our_chassis = false;\n     if (iface_rec\n         || (binding_rec->parent_port && binding_rec->parent_port[0] &&\n             sset_contains(local_lports, binding_rec->parent_port))) {\n@@ -398,83 +399,93 @@ consider_local_datapath(struct controller_ctx *ctx,\n         if (iface_rec && qos_map && ctx->ovs_idl_txn) {\n             get_qos_params(binding_rec, qos_map);\n         }\n+\n         /* This port is in our chassis unless it is a localport. */\n-       if (strcmp(binding_rec->type, \"localport\")) {\n-            our_chassis = true;\n-        }\n-    } else if (!strcmp(binding_rec->type, \"l2gateway\")) {\n-        const char *chassis_id = smap_get(&binding_rec->options,\n-                                          \"l2gateway-chassis\");\n-        our_chassis = chassis_id && !strcmp(chassis_id, chassis_rec->name);\n-        if (our_chassis) {\n+        return strcmp(binding_rec->type, \"localport\");\n+    }\n+    if (!strcmp(binding_rec->type, \"l2gateway\")) {\n+        if (!strcmp(smap_get_def(&binding_rec->options,\n+                        \"l2gateway-chassis\", \"\"), chassis_rec->name)) {\n             sset_add(local_lports, binding_rec->logical_port);\n             add_local_datapath(ctx, binding_rec->datapath,\n                                false, local_datapaths);\n+            return true;\n         }\n-    } else if (!strcmp(binding_rec->type, \"chassisredirect\")) {\n+        return false;\n+    }\n+    if (!strcmp(binding_rec->type, \"chassisredirect\")) {\n         gateway_chassis = gateway_chassis_get_ordered(binding_rec,\n-                                                       chassis_index);\n+                                                      chassis_index);\n+        bool should_own = false;\n         if (gateway_chassis &&\n             gateway_chassis_contains(gateway_chassis, chassis_rec)) {\n \n-            our_chassis = gateway_chassis_is_active(\n+            should_own = gateway_chassis_is_active(\n                 gateway_chassis, chassis_rec, active_tunnels);\n \n             add_local_datapath(ctx, binding_rec->datapath,\n                                false, local_datapaths);\n         }\n         gateway_chassis_destroy(gateway_chassis);\n-    } else if (!strcmp(binding_rec->type, \"l3gateway\")) {\n-        const char *chassis_id = smap_get(&binding_rec->options,\n-                                          \"l3gateway-chassis\");\n-        our_chassis = chassis_id && !strcmp(chassis_id, chassis_rec->name);\n-        if (our_chassis) {\n+        return should_own;\n+    }\n+    if (!strcmp(binding_rec->type, \"l3gateway\")) {\n+        if (!strcmp(smap_get_def(&binding_rec->options,\n+                        \"l3gateway-chassis\", \"\"), chassis_rec->name)) {\n             add_local_datapath(ctx, binding_rec->datapath,\n                                true, local_datapaths);\n+            return true;\n         }\n-    } else if (!strcmp(binding_rec->type, \"localnet\")) {\n+        return false;\n+    }\n+    if (!strcmp(binding_rec->type, \"localnet\")) {\n         /* Add all localnet ports to local_lports so that we allocate ct zones\n          * for them. */\n         sset_add(local_lports, binding_rec->logical_port);\n-        our_chassis = false;\n-    }\n-\n-    if (ctx->ovnsb_idl_txn) {\n-        const char *vif_chassis = smap_get(&binding_rec->options,\n-                                           \"requested-chassis\");\n-        bool can_bind = !vif_chassis || !vif_chassis[0] ||\n-                        !strcmp(vif_chassis, chassis_rec->name);\n-\n-        if (can_bind && our_chassis) {\n-            if (binding_rec->chassis != chassis_rec) {\n-                if (binding_rec->chassis) {\n-                    VLOG_INFO(\"Changing chassis for lport %s from %s to %s.\",\n-                              binding_rec->logical_port,\n-                              binding_rec->chassis->name,\n-                              chassis_rec->name);\n-                } else {\n-                    VLOG_INFO(\"Claiming lport %s for this chassis.\",\n-                              binding_rec->logical_port);\n-                }\n-                for (int i = 0; i < binding_rec->n_mac; i++) {\n-                    VLOG_INFO(\"%s: Claiming %s\",\n-                              binding_rec->logical_port, binding_rec->mac[i]);\n-                }\n-                sbrec_port_binding_set_chassis(binding_rec, chassis_rec);\n+        return false;\n+    }\n+    return false;\n+}\n+\n+static void\n+update_binding_ownership(const struct sbrec_chassis *chassis_rec,\n+                         const struct sbrec_port_binding *binding_rec,\n+                         bool should_own)\n+{\n+    const char *vif_chassis = smap_get(&binding_rec->options,\n+                                       \"requested-chassis\");\n+    bool can_bind = !vif_chassis || !vif_chassis[0] ||\n+                    !strcmp(vif_chassis, chassis_rec->name);\n+\n+    if (should_own && can_bind) {\n+        if (binding_rec->chassis != chassis_rec) {\n+            if (binding_rec->chassis) {\n+                VLOG_INFO(\"Changing chassis for lport %s from %s to %s.\",\n+                          binding_rec->logical_port,\n+                          binding_rec->chassis->name,\n+                          chassis_rec->name);\n+            } else {\n+                VLOG_INFO(\"Claiming lport %s for this chassis.\",\n+                          binding_rec->logical_port);\n             }\n-        } else if (binding_rec->chassis == chassis_rec) {\n-            VLOG_INFO(\"Releasing lport %s from this chassis.\",\n-                      binding_rec->logical_port);\n-            sbrec_port_binding_set_chassis(binding_rec, NULL);\n-        } else if (our_chassis) {\n-            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);\n-            VLOG_INFO_RL(&rl,\n-                         \"Not claiming lport %s, chassis %s \"\n-                         \"requested-chassis %s\",\n-                         binding_rec->logical_port,\n-                         chassis_rec->name,\n-                         vif_chassis);\n+            for (int i = 0; i < binding_rec->n_mac; i++) {\n+                VLOG_INFO(\"%s: Claiming %s\",\n+                          binding_rec->logical_port, binding_rec->mac[i]);\n+            }\n+            sbrec_port_binding_set_chassis(binding_rec, chassis_rec);\n         }\n+    } else if (binding_rec->chassis == chassis_rec) {\n+        VLOG_INFO(\"Releasing lport %s from this chassis.\",\n+                  binding_rec->logical_port);\n+        sbrec_port_binding_set_chassis(binding_rec, NULL);\n+    } else if (should_own) {\n+        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);\n+        VLOG_INFO_RL(&rl,\n+                     \"Not claiming lport %s, chassis %s \"\n+                     \"requested-chassis %s\",\n+                     binding_rec->logical_port,\n+                     chassis_rec->name,\n+                     vif_chassis);\n     }\n }\n \n@@ -502,38 +513,31 @@ consider_localnet_port(const struct sbrec_port_binding *binding_rec,\n     ld->localnet_port = binding_rec;\n }\n \n-void\n-binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,\n+static void\n+binding_run__(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,\n             const struct sbrec_chassis *chassis_rec,\n             const struct chassis_index *chassis_index,\n-            struct sset *active_tunnels,\n-            struct hmap *local_datapaths, struct sset *local_lports)\n+            struct sset *active_tunnels, struct hmap *qos_map,\n+            struct hmap *local_datapaths, struct sset *local_lports,\n+            bool update_sb)\n {\n-    if (!chassis_rec) {\n-        return;\n-    }\n-\n     const struct sbrec_port_binding *binding_rec;\n     struct shash lport_to_iface = SHASH_INITIALIZER(&lport_to_iface);\n-    struct sset egress_ifaces = SSET_INITIALIZER(&egress_ifaces);\n-    struct hmap qos_map;\n-\n-    hmap_init(&qos_map);\n     if (br_int) {\n-        get_local_iface_ids(br_int, &lport_to_iface, local_lports,\n-                            &egress_ifaces);\n+        get_local_iface_ids(br_int, &lport_to_iface, local_lports);\n     }\n \n     /* Run through each binding record to see if it is resident on this\n      * chassis and update the binding accordingly.  This includes both\n      * directly connected logical ports and children of those ports. */\n     SBREC_PORT_BINDING_FOR_EACH(binding_rec, ctx->ovnsb_idl) {\n-        consider_local_datapath(ctx, chassis_index,\n-                                active_tunnels, chassis_rec, binding_rec,\n-                                sset_is_empty(&egress_ifaces) ? NULL :\n-                                &qos_map, local_datapaths, &lport_to_iface,\n-                                local_lports);\n+        bool should_own = consider_local_datapath(\n+            ctx, chassis_index, active_tunnels, chassis_rec, binding_rec,\n+            qos_map, local_datapaths, &lport_to_iface, local_lports);\n \n+        if (ctx->ovnsb_idl_txn && update_sb) {\n+            update_binding_ownership(chassis_rec, binding_rec, should_own);\n+        }\n     }\n \n     /* Run through each binding record to see if it is a localnet port\n@@ -545,6 +549,34 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,\n         }\n     }\n \n+    shash_destroy(&lport_to_iface);\n+}\n+\n+/* Initializes 'local_datapaths' and 'local_lports' to the sets of logical\n+ * datapaths and logical ports, respectively, that are relevant to this\n+ * machine.  Updates Port_Binding records 'chassis' columns to point to\n+ * 'chassis_rec' where appropriate.  Sets up QoS appropriately on tunnel egress\n+ * interfaces. */\n+void\n+binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,\n+            const struct sbrec_chassis *chassis_rec,\n+            const struct chassis_index *chassis_index,\n+            struct sset *active_tunnels,\n+            struct hmap *local_datapaths, struct sset *local_lports)\n+{\n+    if (!chassis_rec) {\n+        return;\n+    }\n+\n+    struct sset egress_ifaces = SSET_INITIALIZER(&egress_ifaces);\n+    if (br_int) {\n+        get_egress_ifaces(br_int, &egress_ifaces);\n+    }\n+\n+    struct hmap qos_map = HMAP_INITIALIZER(&qos_map);\n+    binding_run__(ctx, br_int, chassis_rec, chassis_index, active_tunnels,\n+                  sset_is_empty(&egress_ifaces) ? NULL : &qos_map,\n+                  local_datapaths, local_lports, true);\n     if (!sset_is_empty(&egress_ifaces)\n         && set_noop_qos(ctx, &egress_ifaces)) {\n         const char *entry;\n@@ -552,10 +584,26 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,\n             setup_qos(entry, &qos_map);\n         }\n     }\n-\n-    shash_destroy(&lport_to_iface);\n-    sset_destroy(&egress_ifaces);\n     hmap_destroy(&qos_map);\n+    sset_destroy(&egress_ifaces);\n+}\n+\n+/* Initializes 'local_datapaths' and 'local_lports' to the sets of logical\n+ * datapaths and logical ports, respectively, that are relevant to this\n+ * machine. */\n+void\n+binding_get(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,\n+            const struct sbrec_chassis *chassis_rec,\n+            const struct chassis_index *chassis_index,\n+            struct sset *active_tunnels,\n+            struct hmap *local_datapaths, struct sset *local_lports)\n+{\n+    if (!chassis_rec) {\n+        return;\n+    }\n+\n+    binding_run__(ctx, br_int, chassis_rec, chassis_index, active_tunnels, NULL,\n+                  local_datapaths, local_lports, false);\n }\n \n /* Returns true if the database is all cleaned up, false if more work is\ndiff --git a/ovn/controller/binding.h b/ovn/controller/binding.h\nindex c78f8d9..e53000e 100644\n--- a/ovn/controller/binding.h\n+++ b/ovn/controller/binding.h\n@@ -33,6 +33,11 @@ void binding_run(struct controller_ctx *, const struct ovsrec_bridge *br_int,\n                  const struct chassis_index *,\n                  struct sset *active_tunnels, struct hmap *local_datapaths,\n                  struct sset *all_lports);\n+void binding_get(struct controller_ctx *, const struct ovsrec_bridge *br_int,\n+                 const struct sbrec_chassis *,\n+                 const struct chassis_index *,\n+                 struct sset *active_tunnels, struct hmap *local_datapaths,\n+                 struct sset *all_lports);\n bool binding_cleanup(struct controller_ctx *, const struct sbrec_chassis *);\n \n #endif /* ovn/binding.h */\ndiff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c\nindex e2c9652..2dacba1 100644\n--- a/ovn/controller/ovn-controller.c\n+++ b/ovn/controller/ovn-controller.c\n@@ -204,15 +204,26 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl,\n     ovsdb_idl_condition_destroy(&dns);\n }\n \n+static const char *\n+br_int_name(const struct ovsrec_open_vswitch *cfg)\n+{\n+    return smap_get_def(&cfg->external_ids, \"ovn-bridge\", DEFAULT_BRIDGE_NAME);\n+}\n+\n static const struct ovsrec_bridge *\n-create_br_int(struct controller_ctx *ctx,\n-              const struct ovsrec_open_vswitch *cfg,\n-              const char *bridge_name)\n+create_br_int(struct controller_ctx *ctx)\n {\n     if (!ctx->ovs_idl_txn) {\n         return NULL;\n     }\n \n+    const struct ovsrec_open_vswitch *cfg;\n+    cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);\n+    if (!cfg) {\n+        return NULL;\n+    }\n+    const char *bridge_name = br_int_name(cfg);\n+\n     ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn,\n             \"ovn-controller: creating integration bridge '%s'\", bridge_name);\n \n@@ -255,15 +266,7 @@ get_br_int(struct controller_ctx *ctx)\n         return NULL;\n     }\n \n-    const char *br_int_name = smap_get_def(&cfg->external_ids, \"ovn-bridge\",\n-                                           DEFAULT_BRIDGE_NAME);\n-\n-    const struct ovsrec_bridge *br;\n-    br = get_bridge(ctx->ovs_idl, br_int_name);\n-    if (!br) {\n-        return create_br_int(ctx, cfg, br_int_name);\n-    }\n-    return br;\n+    return get_bridge(ctx->ovs_idl, br_int_name(cfg));\n }\n \n static const char *\n@@ -673,6 +676,9 @@ main(int argc, char *argv[])\n         struct sset active_tunnels = SSET_INITIALIZER(&active_tunnels);\n \n         const struct ovsrec_bridge *br_int = get_br_int(&ctx);\n+        if (!br_int) {\n+            br_int = create_br_int(&ctx);\n+        }\n         const char *chassis_id = get_chassis_id(ctx.ovs_idl);\n \n         struct chassis_index chassis_index;\n",
    "prefixes": [
        "ovs-dev",
        "v4",
        "1/3"
    ]
}