ebb439
From 4027dae96c587d68a7c15b798a7016cffbe9fd48 Mon Sep 17 00:00:00 2001
ebb439
From: Dumitru Ceara <dceara@redhat.com>
ebb439
Date: Tue, 3 Nov 2020 16:51:04 +0100
ebb439
Subject: [PATCH 1/2] pinctrl: Directly update MAC_Bindings created by self
ebb439
 originated GARPs.
ebb439
ebb439
OVN uses GARPs to announce changes to locally owned NAT addresses.  This is
ebb439
OK when updating upstream router caches but is unnecessary for updating OVN
ebb439
logical router MAC_Bindings.
ebb439
ebb439
ovn-controller already has the information required for directly
ebb439
updating/inserting the MAC_Bindings that would be created by neighbor
ebb439
routers.
ebb439
ebb439
This also has the advantage that GARPs don't necessarily need to be flooded
ebb439
in the complete L2 domain of the switch and that router patch ports can be
ebb439
skipped.  An upcoming commit will take advantage of this.
ebb439
ebb439
Suggested-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
ebb439
Fixes: 81e928526b8a ("ovn-controller: Inject GARPs to logical switch pipeline to update neighbors")
ebb439
Acked-by: Mark Michelson <mmichels@redhat.com>
ebb439
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
ebb439
Signed-off-by: Numan Siddique <numans@ovn.org>
ebb439
(cherry picked from upstream commit a2b88dc5136507e727e4bcdc4bf6fde559f519a9)
ebb439
ebb439
Change-Id: I2209707359d268e7d80ed114e187e7ff13e7176c
ebb439
---
ebb439
 controller/pinctrl.c | 105 +++++++++++++++++++++++++++++++++++++++++----------
ebb439
 1 file changed, 85 insertions(+), 20 deletions(-)
ebb439
ebb439
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
ebb439
index f15afc5..dd9fff9 100644
ebb439
--- a/controller/pinctrl.c
ebb439
+++ b/controller/pinctrl.c
ebb439
@@ -200,8 +200,10 @@ static void init_send_garps_rarps(void);
ebb439
 static void destroy_send_garps_rarps(void);
ebb439
 static void send_garp_rarp_wait(long long int send_garp_rarp_time);
ebb439
 static void send_garp_rarp_prepare(
ebb439
+    struct ovsdb_idl_txn *ovnsb_idl_txn,
ebb439
     struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
ebb439
     struct ovsdb_idl_index *sbrec_port_binding_by_name,
ebb439
+    struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
ebb439
     const struct ovsrec_bridge *,
ebb439
     const struct sbrec_chassis *,
ebb439
     const struct hmap *local_datapaths,
ebb439
@@ -3145,8 +3147,9 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
ebb439
                          sbrec_mac_binding_by_lport_ip);
ebb439
     run_put_vport_bindings(ovnsb_idl_txn, sbrec_datapath_binding_by_key,
ebb439
                            sbrec_port_binding_by_key, chassis);
ebb439
-    send_garp_rarp_prepare(sbrec_port_binding_by_datapath,
ebb439
-                           sbrec_port_binding_by_name, br_int, chassis,
ebb439
+    send_garp_rarp_prepare(ovnsb_idl_txn, sbrec_port_binding_by_datapath,
ebb439
+                           sbrec_port_binding_by_name,
ebb439
+                           sbrec_mac_binding_by_lport_ip, br_int, chassis,
ebb439
                            local_datapaths, active_tunnels);
ebb439
     prepare_ipv6_ras(local_datapaths);
ebb439
     prepare_ipv6_prefixd(ovnsb_idl_txn, sbrec_port_binding_by_name,
ebb439
@@ -3837,6 +3840,64 @@ mac_binding_lookup(struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
ebb439
     return retval;
ebb439
 }
ebb439
 
ebb439
+/* Update or add an IP-MAC binding for 'logical_port'. */
ebb439
+static void
ebb439
+mac_binding_add(struct ovsdb_idl_txn *ovnsb_idl_txn,
ebb439
+                struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
ebb439
+                const char *logical_port,
ebb439
+                const struct sbrec_datapath_binding *dp,
ebb439
+                struct eth_addr ea, const char *ip)
ebb439
+{
ebb439
+    /* Convert ethernet argument to string form for database. */
ebb439
+    char mac_string[ETH_ADDR_STRLEN + 1];
ebb439
+    snprintf(mac_string, sizeof mac_string, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
ebb439
+
ebb439
+    const struct sbrec_mac_binding *b =
ebb439
+        mac_binding_lookup(sbrec_mac_binding_by_lport_ip, logical_port, ip);
ebb439
+    if (!b) {
ebb439
+        b = sbrec_mac_binding_insert(ovnsb_idl_txn);
ebb439
+        sbrec_mac_binding_set_logical_port(b, logical_port);
ebb439
+        sbrec_mac_binding_set_ip(b, ip);
ebb439
+        sbrec_mac_binding_set_mac(b, mac_string);
ebb439
+        sbrec_mac_binding_set_datapath(b, dp);
ebb439
+    } else if (strcmp(b->mac, mac_string)) {
ebb439
+        sbrec_mac_binding_set_mac(b, mac_string);
ebb439
+    }
ebb439
+}
ebb439
+
ebb439
+/* Simulate the effect of a GARP on local datapaths, i.e., create MAC_Bindings
ebb439
+ * on peer router datapaths.
ebb439
+ */
ebb439
+static void
ebb439
+send_garp_locally(struct ovsdb_idl_txn *ovnsb_idl_txn,
ebb439
+                  struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
ebb439
+                  const struct hmap *local_datapaths,
ebb439
+                  const struct sbrec_port_binding *in_pb,
ebb439
+                  struct eth_addr ea, ovs_be32 ip)
ebb439
+{
ebb439
+    const struct local_datapath *ldp =
ebb439
+        get_local_datapath(local_datapaths, in_pb->datapath->tunnel_key);
ebb439
+
ebb439
+    ovs_assert(ldp);
ebb439
+    for (size_t i = 0; i < ldp->n_peer_ports; i++) {
ebb439
+        const struct sbrec_port_binding *local = ldp->peer_ports[i].local;
ebb439
+        const struct sbrec_port_binding *remote = ldp->peer_ports[i].remote;
ebb439
+
ebb439
+        /* Skip "ingress" port. */
ebb439
+        if (local == in_pb) {
ebb439
+            continue;
ebb439
+        }
ebb439
+
ebb439
+        struct ds ip_s = DS_EMPTY_INITIALIZER;
ebb439
+
ebb439
+        ip_format_masked(ip, OVS_BE32_MAX, &ip_s);
ebb439
+        mac_binding_add(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
ebb439
+                        remote->logical_port, remote->datapath,
ebb439
+                        ea, ds_cstr(&ip_s));
ebb439
+        ds_destroy(&ip_s);
ebb439
+    }
ebb439
+}
ebb439
+
ebb439
 static void
ebb439
 run_put_mac_binding(struct ovsdb_idl_txn *ovnsb_idl_txn,
ebb439
                     struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
ebb439
@@ -3863,20 +3924,8 @@ run_put_mac_binding(struct ovsdb_idl_txn *ovnsb_idl_txn,
ebb439
 
ebb439
     struct ds ip_s = DS_EMPTY_INITIALIZER;
ebb439
     ipv6_format_mapped(&pmb->ip_key, &ip_s);
ebb439
-
ebb439
-    /* Update or add an IP-MAC binding for this logical port. */
ebb439
-    const struct sbrec_mac_binding *b =
ebb439
-        mac_binding_lookup(sbrec_mac_binding_by_lport_ip, pb->logical_port,
ebb439
-                           ds_cstr(&ip_s));
ebb439
-    if (!b) {
ebb439
-        b = sbrec_mac_binding_insert(ovnsb_idl_txn);
ebb439
-        sbrec_mac_binding_set_logical_port(b, pb->logical_port);
ebb439
-        sbrec_mac_binding_set_ip(b, ds_cstr(&ip_s));
ebb439
-        sbrec_mac_binding_set_mac(b, mac_string);
ebb439
-        sbrec_mac_binding_set_datapath(b, pb->datapath);
ebb439
-    } else if (strcmp(b->mac, mac_string)) {
ebb439
-        sbrec_mac_binding_set_mac(b, mac_string);
ebb439
-    }
ebb439
+    mac_binding_add(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
ebb439
+                    pb->logical_port, pb->datapath, pmb->mac, ds_cstr(&ip_s));
ebb439
     ds_destroy(&ip_s);
ebb439
 }
ebb439
 
ebb439
@@ -4018,7 +4067,10 @@ add_garp_rarp(const char *name, const struct eth_addr ea, ovs_be32 ip,
ebb439
 
ebb439
 /* Add or update a vif for which GARPs need to be announced. */
ebb439
 static void
ebb439
-send_garp_rarp_update(const struct sbrec_port_binding *binding_rec,
ebb439
+send_garp_rarp_update(struct ovsdb_idl_txn *ovnsb_idl_txn,
ebb439
+                      struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
ebb439
+                      const struct hmap *local_datapaths,
ebb439
+                      const struct sbrec_port_binding *binding_rec,
ebb439
                       struct shash *nat_addresses)
ebb439
 {
ebb439
     volatile struct garp_rarp_data *garp_rarp = NULL;
ebb439
@@ -4044,6 +4096,11 @@ send_garp_rarp_update(const struct sbrec_port_binding *binding_rec,
ebb439
                                   laddrs->ipv4_addrs[i].addr,
ebb439
                                   binding_rec->datapath->tunnel_key,
ebb439
                                   binding_rec->tunnel_key);
ebb439
+                    send_garp_locally(ovnsb_idl_txn,
ebb439
+                                      sbrec_mac_binding_by_lport_ip,
ebb439
+                                      local_datapaths, binding_rec, laddrs->ea,
ebb439
+                                      laddrs->ipv4_addrs[i].addr);
ebb439
+
ebb439
                 }
ebb439
                 free(name);
ebb439
             }
ebb439
@@ -4079,6 +4136,10 @@ send_garp_rarp_update(const struct sbrec_port_binding *binding_rec,
ebb439
                       laddrs.ea, ip,
ebb439
                       binding_rec->datapath->tunnel_key,
ebb439
                       binding_rec->tunnel_key);
ebb439
+        if (ip) {
ebb439
+            send_garp_locally(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
ebb439
+                              local_datapaths, binding_rec, laddrs.ea, ip);
ebb439
+        }
ebb439
 
ebb439
         destroy_lport_addresses(&laddrs);
ebb439
         break;
ebb439
@@ -5355,8 +5416,10 @@ send_garp_rarp_run(struct rconn *swconn, long long int *send_garp_rarp_time)
ebb439
 /* Called by pinctrl_run(). Runs with in the main ovn-controller
ebb439
  * thread context. */
ebb439
 static void
ebb439
-send_garp_rarp_prepare(struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
ebb439
+send_garp_rarp_prepare(struct ovsdb_idl_txn *ovnsb_idl_txn,
ebb439
+                       struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
ebb439
                        struct ovsdb_idl_index *sbrec_port_binding_by_name,
ebb439
+                       struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
ebb439
                        const struct ovsrec_bridge *br_int,
ebb439
                        const struct sbrec_chassis *chassis,
ebb439
                        const struct hmap *local_datapaths,
ebb439
@@ -5395,7 +5458,8 @@ send_garp_rarp_prepare(struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
ebb439
         const struct sbrec_port_binding *pb = lport_lookup_by_name(
ebb439
             sbrec_port_binding_by_name, iface_id);
ebb439
         if (pb) {
ebb439
-            send_garp_rarp_update(pb, &nat_addresses);
ebb439
+            send_garp_rarp_update(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
ebb439
+                                  local_datapaths, pb, &nat_addresses);
ebb439
         }
ebb439
     }
ebb439
 
ebb439
@@ -5405,7 +5469,8 @@ send_garp_rarp_prepare(struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
ebb439
         const struct sbrec_port_binding *pb
ebb439
             = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port);
ebb439
         if (pb) {
ebb439
-            send_garp_rarp_update(pb, &nat_addresses);
ebb439
+            send_garp_rarp_update(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
ebb439
+                                  local_datapaths, pb, &nat_addresses);
ebb439
         }
ebb439
     }
ebb439
 
ebb439
-- 
ebb439
1.8.3.1
ebb439