Hi,

I'd like to propose the following patch to OVN.

The objective here is to copy the external_ids k,v pairs from logical
switch ports with type localnet to the patch ports created between the
br-int and the provider bridge.

This would allow me to implement a custom Openflow pipeline in the
provider bridge for a tenant assigned localnet port.

@Numan Siddique Can you review this and provide some guidance?

 (cd "$(git rev-parse --show-toplevel)" && git apply --3way <<'EOF'
diff --git a/controller/ovn-controller.8.xml b/controller/ovn-controller.8.xml
index 
5007f5f80ad1ae6ae66ddc42ffa89830487df83c..422eb2cf7b976977372e1aedbc5eaa1319ef5340
100644
--- a/controller/ovn-controller.8.xml
+++ b/controller/ovn-controller.8.xml
@@ -532,50 +532,55 @@
         port or gateway router's zone key.  The value for this key
         identifies the zone used for this port.
       </dd>

       <dt>
         <code>external_ids:ovn-localnet-port</code> in the <code>Port</code>
         table
       </dt>
       <dd>
         <p>
           The presence of this key identifies a patch port as one created by
           <code>ovn-controller</code> to connect the integration bridge and
           another bridge to implement a <code>localnet</code> logical port.
           Its value is the name of the logical port with <code>type</code>
           set to <code>localnet</code> that the port implements. See
           <code>external_ids:ovn-bridge-mappings</code>, above, for more
           information.
         </p>

         <p>
           Each <code>localnet</code> logical port is implemented as a pair of
           patch ports, one in the integration bridge, one in a different
           bridge, with the same <code>external_ids:ovn-localnet-port</code>
           value.
         </p>
+        <p>
+          When a <code>localnet</code> port has additional values in its
+          <code>external_ids</code> column, these key-value pairs are copied to
+          the corresponding patch ports.
+        </p>
       </dd>

       <dt>
         <code>external_ids:ovn-l2gateway-port</code> in the <code>Port</code>
         table
       </dt>
       <dd>
         <p>
           The presence of this key identifies a patch port as one created by
           <code>ovn-controller</code> to connect the integration bridge and
           another bridge to implement a <code>l2gateway</code> logical port.
           Its value is the name of the logical port with <code>type</code>
           set to <code>l2gateway</code> that the port implements. See
           <code>external_ids:ovn-bridge-mappings</code>, above, for more
           information.
         </p>

         <p>
           Each <code>l2gateway</code> logical port is implemented as a pair
           of patch ports, one in the integration bridge, one in a different
           bridge, with the same <code>external_ids:ovn-l2gateway-port</code>
           value.
         </p>
       </dd>

diff --git a/controller/patch.c b/controller/patch.c
index 
4fed6e375daf5a1a989d2f9a93aab939eac3d6f4..b83c281624661279a7e2f9f1d4d6e0b9fc400950
100644
--- a/controller/patch.c
+++ b/controller/patch.c
@@ -57,68 +57,76 @@ static bool
 match_patch_port(const struct ovsrec_port *port, const char *peer)
 {
     for (size_t i = 0; i < port->n_interfaces; i++) {
         struct ovsrec_interface *iface = port->interfaces[i];
         if (strcmp(iface->type, "patch")) {
             continue;
         }
         const char *iface_peer = smap_get(&iface->options, "peer");
         if (iface_peer && !strcmp(iface_peer, peer)) {
             return true;
         }
     }
     return false;
 }

 /* Creates a patch port in bridge 'src' named 'src_name', whose peer is
  * 'dst_name' in bridge 'dst'.  Initializes the patch port's external-ids:'key'
  * to 'key'.
  *
  * If such a patch port already exists, removes it from 'existing_ports'. */
 static void
 create_patch_port(struct ovsdb_idl_txn *ovs_idl_txn,
                   const char *key, const char *value,
                   const struct ovsrec_bridge *src, const char *src_name,
                   const struct ovsrec_bridge *dst, const char *dst_name,
-                  struct shash *existing_ports)
+                  struct shash *existing_ports,
+                  const struct smap *extra_ids)
 {
     for (size_t i = 0; i < src->n_ports; i++) {
         if (match_patch_port(src->ports[i], dst_name)) {
             /* Patch port already exists on 'src'. */
             shash_find_and_delete(existing_ports, src->ports[i]->name);
             return;
         }
     }

     ovsdb_idl_txn_add_comment(ovs_idl_txn,
             "ovn-controller: creating patch port '%s' from '%s' to '%s'",
             src_name, src->name, dst->name);

     const struct smap if_options = SMAP_CONST1(&if_options, "peer", dst_name);
-    const struct smap port_ids = SMAP_CONST1(&port_ids, key, value);
+
+    struct smap port_ids = SMAP_INITIALIZER(&port_ids);
+    if (extra_ids) {
+        smap_clone(&port_ids, extra_ids);
+    }
+    smap_replace(&port_ids, key, value);
+
     ovsport_create(ovs_idl_txn, src, src_name, "patch", &port_ids, NULL,
                    &if_options, 0);
+    smap_destroy(&port_ids);
 }

 static void
 remove_port(const struct ovsrec_bridge_table *bridge_table,
             const struct ovsrec_port *port)
 {
     const struct ovsrec_bridge *bridge;

     /* We know the port we want to delete, but we have to find the bridge its
      * on to do so.  Note this only runs on a config change that should be
      * pretty rare. */
     OVSREC_BRIDGE_TABLE_FOR_EACH (bridge, bridge_table) {
         size_t i;
         for (i = 0; i < bridge->n_ports; i++) {
             if (bridge->ports[i] != port) {
                 continue;
             }
             ovsport_remove(bridge, port);
             return;
         }
     }
 }

 void
 add_ovs_bridge_mappings(const struct ovsrec_open_vswitch_table *ovs_table,
@@ -201,56 +209,61 @@ add_bridge_mappings_by_type(struct ovsdb_idl_txn
*ovs_idl_txn,
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
             VLOG_ERR_RL(&rl, "%s port '%s' has no network name.",
                          binding->type, binding->logical_port);
             continue;
         }
         char *msg_key = xasprintf("%s;%s", binding->logical_port, network);
         struct ovsrec_bridge *br_ln =
shash_find_data(bridge_mappings, network);
         if (!br_ln) {
             if (log_missing_bridge) {
                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
                 VLOG_ERR_RL(&rl, "bridge not found for %s port '%s' "
                             "with network name '%s'",
                             binding->type, binding->logical_port, network);
             } else if (!sset_contains(&missed_bridges, msg_key)) {
                 VLOG_INFO("bridge not found for %s port '%s' with "
                           "network name '%s'; skipping",
                           binding->type, binding->logical_port, network);
                 sset_add(&missed_bridges, msg_key);
             }
             free(msg_key);
             continue;
         }
         sset_find_and_delete(&missed_bridges, msg_key);
         free(msg_key);

+        const struct smap *extra_ids =
+            !strcmp(pb_type, "localnet") ? &binding->external_ids : NULL;
+
         char *name1 = patch_port_name(br_int->name, binding->logical_port);
         char *name2 = patch_port_name(binding->logical_port, br_int->name);
         create_patch_port(ovs_idl_txn, patch_port_id, binding->logical_port,
-                          br_int, name1, br_ln, name2, existing_ports);
+                          br_int, name1, br_ln, name2, existing_ports,
+                          extra_ids);
         create_patch_port(ovs_idl_txn, patch_port_id, binding->logical_port,
-                          br_ln, name2, br_int, name1, existing_ports);
+                          br_ln, name2, br_int, name1, existing_ports,
+                          extra_ids);
         free(name1);
         free(name2);
     }
     sbrec_port_binding_index_destroy_row(target);
 }

 /* Obtains external-ids:ovn-bridge-mappings from OVSDB and adds patch ports for
  * the local bridge mappings.  Removes any patch ports for bridge mappings that
  * already existed from 'existing_ports'. */
 static void
 add_bridge_mappings(struct ovsdb_idl_txn *ovs_idl_txn,
                     struct ovsdb_idl_index *sbrec_port_binding_by_type,
                     const struct ovsrec_bridge_table *bridge_table,
                     const struct ovsrec_open_vswitch_table *ovs_table,
                     const struct ovsrec_bridge *br_int,
                     struct shash *existing_ports,
                     const struct sbrec_chassis *chassis,
                     const struct hmap *local_datapaths)
 {
     /* Get ovn-bridge-mappings. */
     struct shash bridge_mappings = SHASH_INITIALIZER(&bridge_mappings);

     add_ovs_bridge_mappings(ovs_table, bridge_table, &bridge_mappings);

     add_bridge_mappings_by_type(ovs_idl_txn, sbrec_port_binding_by_type,

EOF
)


Regards

Gav
_______________________________________________
discuss mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-discuss

Reply via email to