get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 1524522,
    "url": "http://patchwork.ozlabs.org/api/patches/1524522/",
    "web_url": "http://patchwork.ozlabs.org/project/ovn/patch/20210903192748.1408062-2-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-2-frode.nordahl@canonical.com>",
    "list_archive_url": null,
    "date": "2021-09-03T19:27:40",
    "name": "[ovs-dev,v4,1/9] ovn-sb: Add requested_chassis column to Port_Binding.",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "1083533b07c4450cb7931da2912b637affa8bafe",
    "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-2-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/1524522/comments/",
    "check": "fail",
    "checks": "http://patchwork.ozlabs.org/api/patches/1524522/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=jRlGssJu;\n\tdkim-atps=neutral",
            "ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=140.211.166.138; helo=smtp1.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN>)",
            "smtp2.osuosl.org (amavisd-new);\n dkim=pass (2048-bit key) header.d=canonical.com"
        ],
        "Received": [
            "from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138])\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 4H1SWG6dS0z9sSs\n\tfor <incoming@patchwork.ozlabs.org>; Sat,  4 Sep 2021 05:28:10 +1000 (AEST)",
            "from localhost (localhost [127.0.0.1])\n\tby smtp1.osuosl.org (Postfix) with ESMTP id 907C383F31;\n\tFri,  3 Sep 2021 19:28:08 +0000 (UTC)",
            "from smtp1.osuosl.org ([127.0.0.1])\n\tby localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id KJAFwjWHzvwx; Fri,  3 Sep 2021 19:28:04 +0000 (UTC)",
            "from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])\n\tby smtp1.osuosl.org (Postfix) with ESMTPS id 9664E83F2D;\n\tFri,  3 Sep 2021 19:28:02 +0000 (UTC)",
            "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 1F6C5C0033;\n\tFri,  3 Sep 2021 19:27:59 +0000 (UTC)",
            "from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 4FD48C0023\n for <dev@openvswitch.org>; Fri,  3 Sep 2021 19:27:55 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by smtp2.osuosl.org (Postfix) with ESMTP id 7CCA64027D\n for <dev@openvswitch.org>; Fri,  3 Sep 2021 19:27:54 +0000 (UTC)",
            "from smtp2.osuosl.org ([127.0.0.1])\n by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n with ESMTP id ukEJMf_QmyTu 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 smtp2.osuosl.org (Postfix) with ESMTPS id 7A569400AE\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 5950C40192;\n Fri,  3 Sep 2021 19:27:49 +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=1630697269;\n bh=qN738PGGkB8fpw63A/O3UUUFmgoFD06EtZii1QjR7TE=;\n h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:\n MIME-Version;\n b=jRlGssJucpj+s0EHB16nZOMsqvdkxvCRhqsLoBKmsdmDFcbQiKsr1QYt45p/hiu03\n PYZb9yaOQPavTlzywYqJVMR9msauZv/VtqTLsQxM/EjdKNJ4OEMgv0Mt9Hsm8Vxw9l\n 5bQjELEBPBHG3W7JE7dOfIKeimKIt1R1ftP7MU7hxqbZSjC03xX0qyr2yl1jEC/NW2\n P5COWbnex42k/+OVSn2LKjzpWTH+RCwKDTGcTxnmqO2lu5qL/T496NvVrzs+nYokOH\n HA2v6G2BsjBSaHegEQWdKIz4JelUMrqBfR1OdLO2GYAKOUhqfmOuJTELic52TWKyeV\n pQH/1oPKkTJFw==",
        "From": "Frode Nordahl <frode.nordahl@canonical.com>",
        "To": "dev@openvswitch.org",
        "Date": "Fri,  3 Sep 2021 21:27:40 +0200",
        "Message-Id": "<20210903192748.1408062-2-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 1/9] ovn-sb: Add requested_chassis column\n\tto Port_Binding.",
        "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": "To allow for ovn-controller to efficiently process unbound ports\nthat may be destined to it, for example for use in the optional\nplugging support, we add a new requested_chassis column with\nweakRef to the Chassis table.  The ovn-controller can monitor\nthis column and only process events for its chassis UUID even\nbefore a local binding appears.\n\nnorthd will fill this column with UUID of Chassis referenced\nin Logical_Switch_Port options:requested-chassis by name or\nhostname.\n\nDeprecate the OVN_Southbound:Port_Binding:options\n\"requested-chassis\" key.  In a subsequent update to the\ncontroller we will improve the efficiency of the requested-chassis\nfeature by using the new column instead of each chassis performing\noption processing and string comparison.\n\nNote that the CMS facing Northbound Logical_Switch_Port:options\nAPI remains the same.\n\nSigned-off-by: Frode Nordahl <frode.nordahl@canonical.com>\n---\n lib/chassis-index.c  |  24 +++++++++\n lib/chassis-index.h  |   3 ++\n northd/ovn-northd.c  |  55 +++++++++++++++++--\n northd/ovn_northd.dl | 124 ++++++++++++++++++++++++++++++++++++++++---\n ovn-nb.xml           |  33 ++++++++++--\n ovn-sb.ovsschema     |  10 ++--\n ovn-sb.xml           |  37 ++++++++++---\n tests/ovn-northd.at  |  45 ++++++++++++++++\n 8 files changed, 307 insertions(+), 24 deletions(-)",
    "diff": "diff --git a/lib/chassis-index.c b/lib/chassis-index.c\nindex 13120fe3e..4b38036cb 100644\n--- a/lib/chassis-index.c\n+++ b/lib/chassis-index.c\n@@ -22,6 +22,12 @@ chassis_index_create(struct ovsdb_idl *idl)\n     return ovsdb_idl_index_create1(idl, &sbrec_chassis_col_name);\n }\n \n+struct ovsdb_idl_index *\n+chassis_hostname_index_create(struct ovsdb_idl *idl)\n+{\n+    return ovsdb_idl_index_create1(idl, &sbrec_chassis_col_hostname);\n+}\n+\n /* Finds and returns the chassis with the given 'name', or NULL if no such\n  * chassis exists. */\n const struct sbrec_chassis *\n@@ -40,6 +46,24 @@ chassis_lookup_by_name(struct ovsdb_idl_index *sbrec_chassis_by_name,\n     return retval;\n }\n \n+/* Finds and returns the chassis with the given 'hostname', or NULL if no such\n+ * chassis exists. */\n+const struct sbrec_chassis *\n+chassis_lookup_by_hostname(struct ovsdb_idl_index *sbrec_chassis_by_hostname,\n+                           const char *hostname)\n+{\n+    struct sbrec_chassis *target = sbrec_chassis_index_init_row(\n+        sbrec_chassis_by_hostname);\n+    sbrec_chassis_index_set_hostname(target, hostname);\n+\n+    struct sbrec_chassis *retval = sbrec_chassis_index_find(\n+        sbrec_chassis_by_hostname, target);\n+\n+    sbrec_chassis_index_destroy_row(target);\n+\n+    return retval;\n+}\n+\n struct ovsdb_idl_index *\n chassis_private_index_create(struct ovsdb_idl *idl)\n {\ndiff --git a/lib/chassis-index.h b/lib/chassis-index.h\nindex b9b331f34..bc654da13 100644\n--- a/lib/chassis-index.h\n+++ b/lib/chassis-index.h\n@@ -19,9 +19,12 @@\n struct ovsdb_idl;\n \n struct ovsdb_idl_index *chassis_index_create(struct ovsdb_idl *);\n+struct ovsdb_idl_index *chassis_hostname_index_create(struct ovsdb_idl *);\n \n const struct sbrec_chassis *chassis_lookup_by_name(\n     struct ovsdb_idl_index *sbrec_chassis_by_name, const char *name);\n+const struct sbrec_chassis *chassis_lookup_by_hostname(\n+    struct ovsdb_idl_index *sbrec_chassis_by_hostname, const char *hostname);\n \n struct ovsdb_idl_index *chassis_private_index_create(struct ovsdb_idl *);\n \ndiff --git a/northd/ovn-northd.c b/northd/ovn-northd.c\nindex ee761cef0..fdcc58e28 100644\n--- a/northd/ovn-northd.c\n+++ b/northd/ovn-northd.c\n@@ -76,6 +76,7 @@ struct northd_context {\n     struct ovsdb_idl_txn *ovnnb_txn;\n     struct ovsdb_idl_txn *ovnsb_txn;\n     struct ovsdb_idl_index *sbrec_chassis_by_name;\n+    struct ovsdb_idl_index *sbrec_chassis_by_hostname;\n     struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name;\n     struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp;\n     struct ovsdb_idl_index *sbrec_ip_mcast_by_dp;\n@@ -3047,6 +3048,7 @@ ovn_update_ipv6_prefix(struct hmap *ports)\n static void\n ovn_port_update_sbrec(struct northd_context *ctx,\n                       struct ovsdb_idl_index *sbrec_chassis_by_name,\n+                      struct ovsdb_idl_index *sbrec_chassis_by_hostname,\n                       const struct ovn_port *op,\n                       struct hmap *chassis_qdisc_queues,\n                       struct sset *active_ha_chassis_grps)\n@@ -3228,6 +3230,36 @@ ovn_port_update_sbrec(struct northd_context *ctx,\n                  * ha_chassis_group cleared in the same transaction. */\n                 sbrec_port_binding_set_ha_chassis_group(op->sb, NULL);\n             }\n+\n+            const char *requested_chassis; /* May be NULL. */\n+            bool reset_requested_chassis = false;\n+            requested_chassis = smap_get(&op->nbsp->options,\n+                                         \"requested-chassis\");\n+            if (requested_chassis) {\n+                const struct sbrec_chassis *chassis; /* May be NULL. */\n+                chassis = chassis_lookup_by_name(sbrec_chassis_by_name,\n+                                                 requested_chassis);\n+                chassis = chassis ? chassis : chassis_lookup_by_hostname(\n+                                sbrec_chassis_by_hostname, requested_chassis);\n+\n+                if (chassis) {\n+                    sbrec_port_binding_set_requested_chassis(op->sb, chassis);\n+                } else {\n+                    reset_requested_chassis = true;\n+                    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(\n+                        1, 1);\n+                    VLOG_WARN_RL(\n+                        &rl,\n+                        \"Unknown chassis '%s' set as \"\n+                        \"options:requested-chassis on LSP '%s'.\",\n+                        requested_chassis, op->nbsp->name);\n+                }\n+            } else if (op->sb->requested_chassis) {\n+                reset_requested_chassis = true;\n+            }\n+            if (reset_requested_chassis) {\n+                sbrec_port_binding_set_requested_chassis(op->sb, NULL);\n+            }\n         } else {\n             const char *chassis = NULL;\n             if (op->peer && op->peer->od && op->peer->od->nbr) {\n@@ -3856,6 +3888,7 @@ ovn_port_allocate_key(struct hmap *ports, struct ovn_port *op)\n static void\n build_ports(struct northd_context *ctx,\n             struct ovsdb_idl_index *sbrec_chassis_by_name,\n+            struct ovsdb_idl_index *sbrec_chassis_by_hostname,\n             struct hmap *datapaths, struct hmap *ports)\n {\n     struct ovs_list sb_only, nb_only, both;\n@@ -3911,6 +3944,7 @@ build_ports(struct northd_context *ctx,\n             tag_alloc_create_new_tag(&tag_alloc_table, op->nbsp);\n         }\n         ovn_port_update_sbrec(ctx, sbrec_chassis_by_name,\n+                              sbrec_chassis_by_hostname,\n                               op, &chassis_qdisc_queues,\n                               &active_ha_chassis_grps);\n     }\n@@ -3918,7 +3952,8 @@ build_ports(struct northd_context *ctx,\n     /* Add southbound record for each unmatched northbound record. */\n     LIST_FOR_EACH_SAFE (op, next, list, &nb_only) {\n         op->sb = sbrec_port_binding_insert(ctx->ovnsb_txn);\n-        ovn_port_update_sbrec(ctx, sbrec_chassis_by_name, op,\n+        ovn_port_update_sbrec(ctx, sbrec_chassis_by_name,\n+                              sbrec_chassis_by_hostname, op,\n                               &chassis_qdisc_queues,\n                               &active_ha_chassis_grps);\n         sbrec_port_binding_set_logical_port(op->sb, op->key);\n@@ -14157,6 +14192,7 @@ get_probe_interval(const char *db, const struct nbrec_nb_global *nb)\n static void\n ovnnb_db_run(struct northd_context *ctx,\n              struct ovsdb_idl_index *sbrec_chassis_by_name,\n+             struct ovsdb_idl_index *sbrec_chassis_by_hostname,\n              struct ovsdb_idl_loop *sb_loop,\n              struct hmap *datapaths, struct hmap *ports,\n              struct ovs_list *lr_list,\n@@ -14260,7 +14296,8 @@ ovnnb_db_run(struct northd_context *ctx,\n     build_datapaths(ctx, datapaths, lr_list);\n     build_ovn_lbs(ctx, datapaths, &lbs);\n     build_lrouter_lbs(datapaths, &lbs);\n-    build_ports(ctx, sbrec_chassis_by_name, datapaths, ports);\n+    build_ports(ctx, sbrec_chassis_by_name, sbrec_chassis_by_hostname,\n+                datapaths, ports);\n     build_ovn_lr_lbs(datapaths, &lbs);\n     build_ovn_lb_svcs(ctx, ports, &lbs);\n     build_ipam(datapaths, ports);\n@@ -14974,6 +15011,7 @@ ovnsb_db_run(struct northd_context *ctx,\n static void\n ovn_db_run(struct northd_context *ctx,\n            struct ovsdb_idl_index *sbrec_chassis_by_name,\n+           struct ovsdb_idl_index *sbrec_chassis_by_hostname,\n            struct ovsdb_idl_loop *ovnsb_idl_loop,\n            const char *ovn_internal_version)\n {\n@@ -14985,8 +15023,8 @@ ovn_db_run(struct northd_context *ctx,\n \n     int64_t start_time = time_wall_msec();\n     stopwatch_start(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec());\n-    ovnnb_db_run(ctx, sbrec_chassis_by_name, ovnsb_idl_loop,\n-                 &datapaths, &ports, &lr_list, start_time,\n+    ovnnb_db_run(ctx, sbrec_chassis_by_name, sbrec_chassis_by_hostname,\n+                 ovnsb_idl_loop, &datapaths, &ports, &lr_list, start_time,\n                  ovn_internal_version);\n     stopwatch_stop(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec());\n     stopwatch_start(OVNSB_DB_RUN_STOPWATCH_NAME, time_msec());\n@@ -15237,6 +15275,8 @@ main(int argc, char *argv[])\n     add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_mac);\n     add_column_noalert(ovnsb_idl_loop.idl,\n                        &sbrec_port_binding_col_nat_addresses);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_port_binding_col_requested_chassis);\n     ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_port_binding_col_chassis);\n     ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n                          &sbrec_port_binding_col_gateway_chassis);\n@@ -15308,6 +15348,7 @@ main(int argc, char *argv[])\n \n     ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis);\n     ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_hostname);\n     ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_other_config);\n     ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_encaps);\n \n@@ -15416,6 +15457,9 @@ main(int argc, char *argv[])\n     struct ovsdb_idl_index *sbrec_chassis_by_name\n         = chassis_index_create(ovnsb_idl_loop.idl);\n \n+    struct ovsdb_idl_index *sbrec_chassis_by_hostname\n+        = chassis_hostname_index_create(ovnsb_idl_loop.idl);\n+\n     struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name\n         = ha_chassis_group_index_create(ovnsb_idl_loop.idl);\n \n@@ -15493,7 +15537,8 @@ main(int argc, char *argv[])\n             }\n \n             if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) {\n-                ovn_db_run(&ctx, sbrec_chassis_by_name, &ovnsb_idl_loop,\n+                ovn_db_run(&ctx, sbrec_chassis_by_name,\n+                           sbrec_chassis_by_hostname, &ovnsb_idl_loop,\n                            ovn_internal_version);\n                 if (ctx.ovnsb_txn) {\n                     check_and_add_supported_dhcp_opts_to_sb_db(&ctx);\ndiff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl\nindex ff92c989c..85c62c547 100644\n--- a/northd/ovn_northd.dl\n+++ b/northd/ovn_northd.dl\n@@ -105,6 +105,22 @@ sb::Out_Datapath_Binding(uuid, tunkey, load_balancers, external_ids) :-\n      */\n     var load_balancers = set_empty().\n \n+function get_requested_chassis(options: Map<string,string>) : string = {\n+    var requested_chassis = match(options.get(\"requested-chassis\")) {\n+        None -> \"\",\n+        Some{requested_chassis} -> requested_chassis,\n+    };\n+    requested_chassis\n+}\n+\n+relation RequestedChassis(\n+    name: string,\n+    chassis: uuid,\n+)\n+RequestedChassis(name, chassis) :-\n+    sb::Chassis(._uuid = chassis, .name=name).\n+RequestedChassis(hostname, chassis) :-\n+    sb::Chassis(._uuid = chassis, .hostname=hostname).\n \n /* Proxy table for Out_Datapath_Binding: contains all Datapath_Binding fields,\n  * except tunnel id, which is allocated separately (see PortTunKeyAllocation). */\n@@ -120,10 +136,12 @@ relation OutProxy_Port_Binding (\n     tag: Option<integer>,\n     mac: Set<string>,\n     nat_addresses: Set<string>,\n-    external_ids: Map<string,string>\n+    external_ids: Map<string,string>,\n+    requested_chassis: Option<uuid>\n )\n \n-/* Case 1: Create a Port_Binding per logical switch port that is not of type \"router\" */\n+/* Case 1a: Create a Port_Binding per logical switch port that is not of type\n+ * \"router\" */\n OutProxy_Port_Binding(._uuid              = lsp._uuid,\n                       .logical_port       = lsp.name,\n                       .__type             = lsp.__type,\n@@ -135,7 +153,8 @@ OutProxy_Port_Binding(._uuid              = lsp._uuid,\n                       .tag                = tag,\n                       .mac                = lsp.addresses,\n                       .nat_addresses      = set_empty(),\n-                      .external_ids       = eids) :-\n+                      .external_ids       = eids,\n+                      .requested_chassis  = None) :-\n     sp in &SwitchPort(.lsp = lsp, .sw = sw),\n     SwitchPortNewDynamicTag(lsp._uuid, opt_tag),\n     var tag = match (opt_tag) {\n@@ -143,6 +162,8 @@ OutProxy_Port_Binding(._uuid              = lsp._uuid,\n         Some{t} -> Some{t}\n     },\n     lsp.__type != \"router\",\n+    var chassis_name_or_hostname = get_requested_chassis(lsp.options),\n+    chassis_name_or_hostname == \"\",\n     var eids = {\n         var eids = lsp.external_ids;\n         match (lsp.external_ids.get(\"neutron:port_name\")) {\n@@ -160,6 +181,91 @@ OutProxy_Port_Binding(._uuid              = lsp._uuid,\n         options\n     }.\n \n+/* Case 1b: Create a Port_Binding per logical switch port that is not of type\n+ * \"router\" and has options \"requested-chassis\" pointing at chassis name or\n+ * hostname. */\n+OutProxy_Port_Binding(._uuid              = lsp._uuid,\n+                      .logical_port       = lsp.name,\n+                      .__type             = lsp.__type,\n+                      .gateway_chassis    = set_empty(),\n+                      .ha_chassis_group   = sp.hac_group_uuid,\n+                      .options            = options,\n+                      .datapath           = sw._uuid,\n+                      .parent_port        = lsp.parent_name,\n+                      .tag                = tag,\n+                      .mac                = lsp.addresses,\n+                      .nat_addresses      = set_empty(),\n+                      .external_ids       = eids,\n+                      .requested_chassis  = Some{requested_chassis}) :-\n+    sp in &SwitchPort(.lsp = lsp, .sw = sw),\n+    SwitchPortNewDynamicTag(lsp._uuid, opt_tag),\n+    var tag = match (opt_tag) {\n+        None -> lsp.tag,\n+        Some{t} -> Some{t}\n+    },\n+    lsp.__type != \"router\",\n+    var chassis_name_or_hostname = get_requested_chassis(lsp.options),\n+    chassis_name_or_hostname != \"\",\n+    RequestedChassis(chassis_name_or_hostname, requested_chassis),\n+    var eids = {\n+        var eids = lsp.external_ids;\n+        match (lsp.external_ids.get(\"neutron:port_name\")) {\n+            None -> (),\n+            Some{name} -> eids.insert(\"name\", name)\n+        };\n+        eids\n+    },\n+    var options = {\n+        var options = lsp.options;\n+        match (sw.other_config.get(\"vlan-passthru\")) {\n+            Some{\"true\"} -> options.insert(\"vlan-passthru\", \"true\"),\n+            _ -> ()\n+        };\n+        options\n+    }.\n+\n+/* Case 1c: Create a Port_Binding per logical switch port that is not of type\n+ * \"router\" and has options \"requested-chassis\" pointing at non-existent\n+ * chassis name or hostname. */\n+OutProxy_Port_Binding(._uuid              = lsp._uuid,\n+                      .logical_port       = lsp.name,\n+                      .__type             = lsp.__type,\n+                      .gateway_chassis    = set_empty(),\n+                      .ha_chassis_group   = sp.hac_group_uuid,\n+                      .options            = options,\n+                      .datapath           = sw._uuid,\n+                      .parent_port        = lsp.parent_name,\n+                      .tag                = tag,\n+                      .mac                = lsp.addresses,\n+                      .nat_addresses      = set_empty(),\n+                      .external_ids       = eids,\n+                      .requested_chassis  = None) :-\n+    sp in &SwitchPort(.lsp = lsp, .sw = sw),\n+    SwitchPortNewDynamicTag(lsp._uuid, opt_tag),\n+    var tag = match (opt_tag) {\n+        None -> lsp.tag,\n+        Some{t} -> Some{t}\n+    },\n+    lsp.__type != \"router\",\n+    var chassis_name_or_hostname = get_requested_chassis(lsp.options),\n+    chassis_name_or_hostname != \"\",\n+    not RequestedChassis(chassis_name_or_hostname, _),\n+    var eids = {\n+        var eids = lsp.external_ids;\n+        match (lsp.external_ids.get(\"neutron:port_name\")) {\n+            None -> (),\n+            Some{name} -> eids.insert(\"name\", name)\n+        };\n+        eids\n+    },\n+    var options = {\n+        var options = lsp.options;\n+        match (sw.other_config.get(\"vlan-passthru\")) {\n+            Some{\"true\"} -> options.insert(\"vlan-passthru\", \"true\"),\n+            _ -> ()\n+        };\n+        options\n+    }.\n \n /* Case 2: Create a Port_Binding per logical switch port of type \"router\" */\n OutProxy_Port_Binding(._uuid              = lsp._uuid,\n@@ -173,7 +279,8 @@ OutProxy_Port_Binding(._uuid              = lsp._uuid,\n                       .tag                = None,\n                       .mac                = lsp.addresses,\n                       .nat_addresses      = nat_addresses,\n-                      .external_ids       = eids) :-\n+                      .external_ids       = eids,\n+                      .requested_chassis  = None) :-\n     &SwitchPort(.lsp = lsp, .sw = sw, .peer = peer),\n     var eids = {\n         var eids = lsp.external_ids;\n@@ -263,7 +370,8 @@ OutProxy_Port_Binding(._uuid              = lrp._uuid,\n                       .tag                = None, // always empty for router ports\n                       .mac                = set_singleton(\"${lrp.mac} ${lrp.networks.join(\\\" \\\")}\"),\n                       .nat_addresses      = set_empty(),\n-                      .external_ids       = lrp.external_ids) :-\n+                      .external_ids       = lrp.external_ids,\n+                      .requested_chassis  = None) :-\n     rp in &RouterPort(.lrp = lrp, .router = router, .peer = peer),\n     RouterPortRAOptionsComplete(lrp._uuid, options0),\n     (var __type, var options1) = match (router.options.get(\"chassis\")) {\n@@ -471,7 +579,8 @@ OutProxy_Port_Binding(// lrp._uuid is already in use; generate a new UUID by\n                       .tag                = None,  //always empty for router ports\n                       .mac                = set_singleton(\"${lrp.mac} ${lrp.networks.join(\\\" \\\")}\"),\n                       .nat_addresses      = set_empty(),\n-                      .external_ids       = lrp.external_ids) :-\n+                      .external_ids       = lrp.external_ids,\n+                      .requested_chassis  = None) :-\n     DistributedGatewayPort(lrp, lr_uuid),\n     DistributedGatewayPortHAChassisGroup(lrp, hacg_uuid),\n     var redirect_type = match (lrp.options.get(\"redirect-type\")) {\n@@ -516,7 +625,8 @@ sb::Out_Port_Binding(._uuid              = pbinding._uuid,\n                     .mac                = pbinding.mac,\n                     .nat_addresses      = pbinding.nat_addresses,\n                     .external_ids       = pbinding.external_ids,\n-                    .up                 = Some{up}) :-\n+                    .up                 = Some{up},\n+                    .requested_chassis  = pbinding.requested_chassis) :-\n     pbinding in OutProxy_Port_Binding(),\n     PortTunKeyAllocation(pbinding._uuid, tunkey),\n     QueueIDAllocation(pbinding._uuid, qid),\ndiff --git a/ovn-nb.xml b/ovn-nb.xml\nindex 390cc5a44..ef2677d94 100644\n--- a/ovn-nb.xml\n+++ b/ovn-nb.xml\n@@ -995,11 +995,16 @@\n \n         <column name=\"options\" key=\"requested-chassis\">\n           If set, identifies a specific chassis (by name or hostname) that\n-          is allowed to bind this port. Using this option will prevent\n+          is allowed to bind or plug this port.  Using this option will prevent\n           thrashing between two chassis trying to bind the same port during\n-          a live migration. It can also prevent similar thrashing due to a\n+          a live migration.  It can also prevent similar thrashing due to a\n           mis-configuration, if a port is accidentally created on more than\n-          one chassis.\n+          one chassis.  This is also used to allow the controller consider\n+          unbound ports for plugging without having to process ports not\n+          destined for its chassis.\n+\n+          Setting this option is a prerequisite for using the\n+          <ref column=\"options\" key=\"plug-type\"/> option (see below).\n         </column>\n \n         <column name=\"options\" key=\"iface-id-ver\">\n@@ -1028,6 +1033,28 @@\n             DHCP reply.\n           </p>\n         </column>\n+\n+        <group title=\"VIF Plugging Options\">\n+          <column name=\"options\" key=\"plug-type\">\n+            If set, OVN will attempt to to perform plugging of this VIF.  In\n+            order to get this port plugged by the OVN controller, OVN must be\n+            built with support for VIF plugging.  The default behavior is for\n+            the CMS to do the VIF plugging.  Each plug provider have their own\n+            options namespaced by name, for example \"plug:representor:key\".\n+            Please refer to the plug provider documentation for more\n+            information.\n+\n+            Supported values: representor\n+          </column>\n+\n+          <column name=\"options\" key=\"plug-mtu-request\">\n+            Requested MTU for plugged interfaces.  When set the OVN controller\n+            will fill the <ref table=\"Interface\" column=\"mtu_request\"/> column\n+            of the Open vSwitch database's\n+            <ref table=\"Interface\" db=\"vswitch\"/> table.  This in turn will\n+            make OVS vswitchd update the MTU of the linked interface.\n+          </column>\n+        </group>\n       </group>\n \n       <group title=\"Virtual port Options\">\ndiff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema\nindex e5ab41db9..122614dd5 100644\n--- a/ovn-sb.ovsschema\n+++ b/ovn-sb.ovsschema\n@@ -1,7 +1,7 @@\n {\n     \"name\": \"OVN_Southbound\",\n-    \"version\": \"20.20.0\",\n-    \"cksum\": \"605270161 26670\",\n+    \"version\": \"20.21.0\",\n+    \"cksum\": \"2362446865 26963\",\n     \"tables\": {\n         \"SB_Global\": {\n             \"columns\": {\n@@ -232,7 +232,11 @@\n                 \"external_ids\": {\"type\": {\"key\": \"string\",\n                                  \"value\": \"string\",\n                                  \"min\": 0,\n-                                 \"max\": \"unlimited\"}}},\n+                                 \"max\": \"unlimited\"}},\n+                \"requested_chassis\": {\"type\": {\"key\": {\"type\": \"uuid\",\n+                                                       \"refTable\": \"Chassis\",\n+                                                       \"refType\": \"weak\"},\n+                                               \"min\": 0, \"max\": 1}}},\n             \"indexes\": [[\"datapath\", \"tunnel_key\"], [\"logical_port\"]],\n             \"isRoot\": true},\n         \"MAC_Binding\": {\ndiff --git a/ovn-sb.xml b/ovn-sb.xml\nindex 2d4d47d10..c966542e7 100644\n--- a/ovn-sb.xml\n+++ b/ovn-sb.xml\n@@ -2983,6 +2983,26 @@ tcp.flags = RST;\n           </dd>\n         </dl>\n       </column>\n+      <column name=\"requested_chassis\">\n+        If set, identifies a specific chassis that is allowed to bind or plug\n+        this port.  Having a value in this column will prevent thrashing\n+        between two chassis trying to bind the same port during a live\n+        migration.\n+        It can also prevent similar thrashing due to a mis-configuration, if a\n+        port is accidentally created on more than one chassis.  This is also\n+        used to allow the controller consider unbound ports for plugging\n+        without having to process ports not destined for its chassis.\n+\n+        This column must be a\n+        <ref table=\"Chassis\"/> record.  This is populated by\n+        <code>ovn-northd</code> when the <ref\n+        table=\"Logical_Switch_Port\"\n+        column=\"options\"\n+        key=\"requested-chassis\"\n+        db=\"OVN_Northbound\"/>\n+        is defined and contains a string matching the name or hostname of an\n+        existing chassis.\n+      </column>\n     </group>\n \n     <group title=\"Patch Options\">\n@@ -3141,12 +3161,17 @@ tcp.flags = RST;\n       </p>\n \n       <column name=\"options\" key=\"requested-chassis\">\n-        If set, identifies a specific chassis (by name or hostname) that\n-        is allowed to bind this port. Using this option will prevent\n-        thrashing between two chassis trying to bind the same port during\n-        a live migration. It can also prevent similar thrashing due to a\n-        mis-configuration, if a port is accidentally created on more than\n-        one chassis.\n+        Deprecated.  This option has been replaced by a separate column\n+        <ref\n+        table=\"Port_Binding\"\n+        column=\"requested_chassis\"\n+        db=\"OVN_Southbound\"/>\n+        and may at some point in the future no longer be copied over from\n+        <ref\n+        table=\"Logical_Switch_Port\"\n+        column=\"options\"\n+        key=\"requested-chassis\"\n+        db=\"OVN_Northbound\"/>.\n       </column>\n \n       <column name=\"options\" key=\"iface-id-ver\">\ndiff --git a/tests/ovn-northd.at b/tests/ovn-northd.at\nindex 11886b94e..8ccf806c7 100644\n--- a/tests/ovn-northd.at\n+++ b/tests/ovn-northd.at\n@@ -5225,3 +5225,48 @@ AT_CHECK([grep lr_in_gw_redirect lrflows | grep cr-DR | sed 's/table=../table=??\n \n AT_CLEANUP\n ])\n+\n+OVN_FOR_EACH_NORTHD([\n+AT_SETUP([check options:requested-chassis fills requested_chassis col])\n+ovn_start NORTHD_TYPE\n+\n+# Add chassis ch1.\n+check ovn-sbctl chassis-add ch1 geneve 127.0.0.2\n+check ovn-sbctl chassis-add ch2 geneve 127.0.0.3\n+\n+wait_row_count Chassis 2\n+\n+ch1_uuid=`ovn-sbctl --bare --columns _uuid find Chassis name=\"ch1\"`\n+ch2_uuid=`ovn-sbctl --bare --columns _uuid find Chassis name=\"ch2\"`\n+\n+check ovn-sbctl set chassis $ch2_uuid hostname=ch2-hostname\n+\n+ovn-nbctl ls-add S1\n+ovn-nbctl --wait=sb lsp-add S1 S1-vm1\n+ovn-nbctl --wait=sb lsp-add S1 S1-vm2\n+\n+wait_row_count Port_Binding 1 logical_port=S1-vm1 requested_chassis!=$ch1_uuid\n+wait_row_count Port_Binding 1 logical_port=S1-vm2 requested_chassis!=$ch2_uuid\n+\n+ovn-nbctl --wait=sb set logical_switch_port S1-vm1 \\\n+    options:requested-chassis=ch1\n+\n+wait_row_count Port_Binding 1 logical_port=S1-vm1 requested_chassis=$ch1_uuid\n+\n+ovn-nbctl --wait=sb set logical_switch_port S1-vm2 \\\n+    options:requested-chassis=ch2-hostname\n+\n+wait_row_count Port_binding 1 logical-port=S1-vm2 requested_chassis=$ch2_uuid\n+\n+ovn-nbctl --wait=sb remove logical_switch_port S1-vm2 \\\n+    options requested-chassis=ch2-hostname\n+\n+wait_row_count Port_binding 1 logical-port=S1-vm2 requested_chassis!=$ch2_uuid\n+\n+ovn-nbctl --wait=sb set logical_switch_port S1-vm2 \\\n+    options:requested-chassis=ch2\n+\n+wait_row_count Port_binding 1 logical-port=S1-vm2 requested_chassis=$ch2_uuid\n+\n+AT_CLEANUP\n+])\n",
    "prefixes": [
        "ovs-dev",
        "v4",
        "1/9"
    ]
}