This patch introduces a new type of OVN ports called "localport".
These ports will be present in every hypervisor and may have the
same IP/MAC addresses. They are not bound to any chassis and traffic
to these ports will never go through a tunnel.

Its main use case is the metadata API support which relies on a local
agent running on every hypervisor and serving metadata to VM's locally.
This service is described in detail at [0].

TODO: write a test case for localport ports

[0] https://review.openstack.org/#/c/452811/

Signed-off-by: Daniel Alvarez <[email protected]>
---
 ovn/controller/binding.c  | 84 +++++++++++++++++++++++++++++++++++++++--------
 ovn/controller/physical.c |  6 ++++
 ovn/northd/ovn-northd.c   |  6 ++--
 3 files changed, 80 insertions(+), 16 deletions(-)

diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
index 95e9deb..1eff3d4 100644
--- a/ovn/controller/binding.c
+++ b/ovn/controller/binding.c
@@ -352,6 +352,43 @@ setup_qos(const char *egress_iface, struct hmap *queue_map)
     hmap_destroy(&consistent_queues);
     netdev_close(netdev_phy);
 }
+static bool
+set_ovsport_external_ids(struct controller_ctx *ctx,
+                         const struct ovsrec_bridge *bridge,
+                         const struct ovsrec_interface *iface_rec,
+                         const char *key,
+                         const char *value)
+{
+    if (!ctx->ovs_idl_txn) {
+        return false;
+    }
+
+    /* Find the port with this interface and add the key/value pair to its
+     * external_ids. Assume 1-1 relationship between port and interface. */
+    int i;
+    for (i = 0; i < bridge->n_ports; i++) {
+        const struct ovsrec_port *port_rec = bridge->ports[i];
+        int j;
+
+        if (!strcmp(port_rec->name, bridge->name)) {
+            continue;
+        }
+
+        for (j = 0; j < port_rec->n_interfaces; j++) {
+            if (port_rec->interfaces[j] == iface_rec) {
+                struct smap new_ids;
+                smap_clone(&new_ids, &port_rec->external_ids);
+                smap_replace(&new_ids, key, value);
+                ovsrec_port_verify_external_ids(port_rec);
+                ovsrec_port_set_external_ids(port_rec, &new_ids);
+                smap_destroy(&new_ids);
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 
 static void
 consider_local_datapath(struct controller_ctx *ctx,
@@ -359,6 +396,7 @@ consider_local_datapath(struct controller_ctx *ctx,
                         const struct lport_index *lports,
                         const struct sbrec_chassis *chassis_rec,
                         const struct sbrec_port_binding *binding_rec,
+                        const struct ovsrec_bridge *bridge,
                         struct hmap *qos_map,
                         struct hmap *local_datapaths,
                         struct shash *lport_to_iface,
@@ -368,19 +406,37 @@ consider_local_datapath(struct controller_ctx *ctx,
         = shash_find_data(lport_to_iface, binding_rec->logical_port);
 
     bool our_chassis = false;
-    if (iface_rec
-        || (binding_rec->parent_port && binding_rec->parent_port[0] &&
-            sset_contains(local_lports, binding_rec->parent_port))) {
-        if (binding_rec->parent_port && binding_rec->parent_port[0]) {
-            /* Add child logical port to the set of all local ports. */
-            sset_add(local_lports, binding_rec->logical_port);
-        }
-        add_local_datapath(ldatapaths, lports, binding_rec->datapath,
-                           false, local_datapaths);
-        if (iface_rec && qos_map && ctx->ovs_idl_txn) {
-            get_qos_params(binding_rec, qos_map);
+
+    if (iface_rec && !strcmp(binding_rec->type, "localport")) {
+        /* Make sure localport external_id is present, otherwise set it
+            * for both interface and port. This should only happen the first
+            * time. */
+        if (!smap_get(&iface_rec->external_ids, "ovn-localport-port")) {
+            if (set_ovsport_external_ids(ctx, bridge, iface_rec,
+                                         "ovn-localport-port",
+                                         binding_rec->logical_port)) {
+                struct smap new_ids;
+                smap_clone(&new_ids, &iface_rec->external_ids);
+                smap_replace(&new_ids, "ovn-localport-port",
+                             binding_rec->logical_port);
+                ovsrec_interface_verify_external_ids(iface_rec);
+                ovsrec_interface_set_external_ids(iface_rec, &new_ids);
+                smap_destroy(&new_ids);
+            }
         }
-        our_chassis = true;
+    } else if (iface_rec
+               || (binding_rec->parent_port && binding_rec->parent_port[0] &&
+                   sset_contains(local_lports, binding_rec->parent_port))) {
+               if (binding_rec->parent_port && binding_rec->parent_port[0]) {
+                   /* Add child logical port to the set of all local ports. */
+                   sset_add(local_lports, binding_rec->logical_port);
+               }
+               add_local_datapath(ldatapaths, lports, binding_rec->datapath,
+                                  false, local_datapaths);
+               if (iface_rec && qos_map && ctx->ovs_idl_txn) {
+                   get_qos_params(binding_rec, qos_map);
+               }
+               our_chassis = true;
     } else if (!strcmp(binding_rec->type, "l2gateway")) {
         const char *chassis_id = smap_get(&binding_rec->options,
                                           "l2gateway-chassis");
@@ -468,8 +524,8 @@ binding_run(struct controller_ctx *ctx, const struct 
ovsrec_bridge *br_int,
         consider_local_datapath(ctx, ldatapaths, lports,
                                 chassis_rec, binding_rec,
                                 sset_is_empty(&egress_ifaces) ? NULL :
-                                &qos_map, local_datapaths, &lport_to_iface,
-                                local_lports);
+                                br_int, &qos_map, local_datapaths,
+                                &lport_to_iface, local_lports);
 
     }
 
diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
index 0f1aa63..187bff5 100644
--- a/ovn/controller/physical.c
+++ b/ovn/controller/physical.c
@@ -784,6 +784,8 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id 
mff_ovn_geneve,
                                         "ovn-localnet-port");
         const char *l2gateway = smap_get(&port_rec->external_ids,
                                         "ovn-l2gateway-port");
+        const char *localport = smap_get(&port_rec->external_ids,
+                                         "ovn-localport-port");
 
         for (int j = 0; j < port_rec->n_interfaces; j++) {
             const struct ovsrec_interface *iface_rec = port_rec->interfaces[j];
@@ -808,6 +810,10 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id 
mff_ovn_geneve,
                 /* L2 gateway patch ports can be handled just like VIFs. */
                 simap_put(&new_localvif_to_ofport, l2gateway, ofport);
                 break;
+            } else if (localport) {
+                /* localport ports can be handled just like VIFs. */
+                simap_put(&new_localvif_to_ofport, localport, ofport);
+                break;
             } else if (chassis_id) {
                 enum chassis_tunnel_type tunnel_type;
                 if (!strcmp(iface_rec->type, "geneve")) {
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 5a2e5ab..09f55c8 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -3166,9 +3166,11 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap 
*ports,
         /*
          * Add ARP/ND reply flows if either the
          *  - port is up or
-         *  - port type is router
+         *  - port type is router or
+         *  - port type is localport
          */
-        if (!lsp_is_up(op->nbsp) && strcmp(op->nbsp->type, "router")) {
+        if (!lsp_is_up(op->nbsp) && strcmp(op->nbsp->type, "router") &&
+            strcmp(op->nbsp->type, "localport")) {
             continue;
         }
 
-- 
1.8.3.1

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

Reply via email to