diff mbox series

[ovs-dev,ovn,v2,08/13] ovn-ic: Interconnection gateway controller.

Message ID 1572469973-2733-9-git-send-email-hzhou@ovn.org
State Superseded
Headers show
Series OVN Interconnection | expand

Commit Message

Han Zhou Oct. 30, 2019, 9:12 p.m. UTC
Sync local and remote gateways between SB and ISB.

Signed-off-by: Han Zhou <hzhou@ovn.org>
---
 ic/ovn-ic.c     | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/ovn-ic.at |  56 +++++++++++++++++++++
 2 files changed, 203 insertions(+)

Comments

Numan Siddique Nov. 12, 2019, 5:51 p.m. UTC | #1
On Thu, Oct 31, 2019 at 2:48 AM Han Zhou <hzhou@ovn.org> wrote:
>
> Sync local and remote gateways between SB and ISB.
>
> Signed-off-by: Han Zhou <hzhou@ovn.org>
> ---
>  ic/ovn-ic.c     | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  tests/ovn-ic.at |  56 +++++++++++++++++++++
>  2 files changed, 203 insertions(+)
>
> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
> index cf9bf96..025aad5 100644
> --- a/ic/ovn-ic.c
> +++ b/ic/ovn-ic.c
> @@ -246,6 +246,152 @@ ts_run(struct ic_context *ctx)
>      shash_destroy(&isb_dps);
>  }
>
> +/* Returns true if any information in gw and chassis is different. */
> +static bool
> +is_gateway_data_changed(const struct isbrec_gateway *gw,
> +                   const struct sbrec_chassis *chassis)
> +{
> +    if (strcmp(gw->hostname, chassis->hostname)) {
> +        return true;
> +    }
> +
> +    if (gw->n_encaps != chassis->n_encaps) {
> +        return true;
> +    }
> +
> +    for (int g = 0; g < gw->n_encaps; g++) {
> +
> +        bool found = false;
> +        const struct isbrec_encap *gw_encap = gw->encaps[g];
> +        for (int s = 0; s < chassis->n_encaps; s++) {
> +            const struct sbrec_encap *chassis_encap = chassis->encaps[s];
> +            if (!strcmp(gw_encap->type, chassis_encap->type) &&
> +                !strcmp(gw_encap->ip, chassis_encap->ip)) {
> +                found = true;
> +                if (!smap_equal(&gw_encap->options, &chassis_encap->options)) {
> +                    return true;
> +                }
> +                break;
> +            }
> +        }
> +        if (!found) {
> +            return true;
> +        }
> +    }
> +
> +    return false;
> +}
> +
> +static void
> +sync_isb_gw_to_sb(struct ic_context *ctx,
> +                  const struct isbrec_gateway *gw,
> +                  const struct sbrec_chassis *chassis)
> +{
> +    sbrec_chassis_set_hostname(chassis, gw->hostname);
> +    sbrec_chassis_set_is_remote(chassis, true);
> +
> +    /* Sync encaps used by this gateway. */
> +    ovs_assert(gw->n_encaps);
> +    struct sbrec_encap *sb_encap;
> +    struct sbrec_encap **sb_encaps =
> +        xmalloc(gw->n_encaps * sizeof *sb_encaps);
> +    for (int i = 0; i < gw->n_encaps; i++) {
> +        sb_encap = sbrec_encap_insert(ctx->ovnsb_txn);
> +        sbrec_encap_set_chassis_name(sb_encap, gw->name);
> +        sbrec_encap_set_ip(sb_encap, gw->encaps[i]->ip);
> +        sbrec_encap_set_type(sb_encap, gw->encaps[i]->type);
> +        sbrec_encap_set_options(sb_encap, &gw->encaps[i]->options);
> +        sb_encaps[i] = sb_encap;
> +    }
> +    sbrec_chassis_set_encaps(chassis, sb_encaps, gw->n_encaps);
> +    free(sb_encaps);
> +}
> +
> +static void
> +sync_sb_gw_to_isb(struct ic_context *ctx,
> +                  const struct sbrec_chassis *chassis,
> +                  const struct isbrec_gateway *gw)
> +{
> +    isbrec_gateway_set_hostname(gw, chassis->hostname);
> +
> +    /* Sync encaps used by this chassis. */
> +    ovs_assert(chassis->n_encaps);
> +    struct isbrec_encap *isb_encap;
> +    struct isbrec_encap **isb_encaps =
> +        xmalloc(chassis->n_encaps * sizeof *isb_encaps);
> +    for (int i = 0; i < chassis->n_encaps; i++) {
> +        isb_encap = isbrec_encap_insert(ctx->ovnisb_txn);
> +        isbrec_encap_set_gateway_name(isb_encap,
> +                                      chassis->name);
> +        isbrec_encap_set_ip(isb_encap, chassis->encaps[i]->ip);
> +        isbrec_encap_set_type(isb_encap,
> +                              chassis->encaps[i]->type);
> +        isbrec_encap_set_options(isb_encap,
> +                                 &chassis->encaps[i]->options);
> +        isb_encaps[i] = isb_encap;
> +    }
> +    isbrec_gateway_set_encaps(gw, isb_encaps,
> +                              chassis->n_encaps);
> +    free(isb_encaps);
> +}
> +
> +static void
> +gateway_run(struct ic_context *ctx, const struct isbrec_availability_zone *az)
> +{
> +    if (!ctx->ovnisb_txn || !ctx->ovnsb_txn) {
> +        return;
> +    }
> +
> +    struct shash local_gws = SHASH_INITIALIZER(&local_gws);
> +    struct shash remote_gws = SHASH_INITIALIZER(&remote_gws);
> +    const struct isbrec_gateway *gw;
> +    ISBREC_GATEWAY_FOR_EACH (gw, ctx->ovnisb_idl) {
> +        if (gw->availability_zone == az) {
> +            shash_add(&local_gws, gw->name, gw);
> +        } else {
> +            shash_add(&remote_gws, gw->name, gw);
> +        }
> +    }
> +
> +    const struct sbrec_chassis *chassis;
> +    SBREC_CHASSIS_FOR_EACH (chassis, ctx->ovnsb_idl) {
> +        if (chassis->is_interconn) {
> +            gw = shash_find_and_delete(&local_gws, chassis->name);
> +            if (!gw) {
> +                gw = isbrec_gateway_insert(ctx->ovnisb_txn);
> +                isbrec_gateway_set_availability_zone(gw, az);
> +                isbrec_gateway_set_name(gw, chassis->name);
> +                sync_sb_gw_to_isb(ctx, chassis, gw);
> +            } else if (is_gateway_data_changed(gw, chassis)) {
> +                sync_sb_gw_to_isb(ctx, chassis, gw);
> +            }
> +        } else if (chassis->is_remote) {
> +            gw = shash_find_and_delete(&remote_gws, chassis->name);
> +            if (!gw) {
> +                sbrec_chassis_delete(chassis);
> +            } else if (is_gateway_data_changed(gw, chassis)) {
> +                sync_isb_gw_to_sb(ctx, gw, chassis);
> +            }
> +        }
> +    }
> +
> +    /* Delete extra gateways from ISB for the local AZ */
> +    struct shash_node *node;
> +    SHASH_FOR_EACH (node, &local_gws) {
> +        isbrec_gateway_delete(node->data);
> +    }
> +    shash_destroy(&local_gws);
> +
> +    /* Create SB chassis for remote gateways in ISB */
> +    SHASH_FOR_EACH (node, &remote_gws) {
> +        gw = node->data;
> +        chassis = sbrec_chassis_insert(ctx->ovnsb_txn);
> +        sbrec_chassis_set_name(chassis, gw->name);
> +        sync_isb_gw_to_sb(ctx, gw, chassis);
> +    }
> +    shash_destroy(&remote_gws);
> +}
> +
>  static void
>  ovn_db_run(struct ic_context *ctx)
>  {
> @@ -257,6 +403,7 @@ ovn_db_run(struct ic_context *ctx)
>      }
>
>      ts_run(ctx);
> +    gateway_run(ctx, az);
>  }
>
>  static void
> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
> index 7e6644d..e5640e4 100644
> --- a/tests/ovn-ic.at
> +++ b/tests/ovn-ic.at
> @@ -68,3 +68,59 @@ ts2
>  OVN_CLEANUP_IC([az1])
>
>  AT_CLEANUP
> +
> +AT_SETUP([ovn-ic -- gateway sync])
> +AT_SKIP_IF([test $HAVE_PYTHON = no])
> +
> +ovn_init_ic_db
> +net_add n1
> +ovn_start az1
> +ovn_start az2
> +sim_add gw1
> +as gw1
> +ovs-vsctl add-br br-phys
> +ovn_az_attach az1 n1 br-phys 192.168.0.1
> +ovs-vsctl set open . external-ids:is-interconn=true
> +
> +AT_CHECK([ovn_as az2 ovn-sbctl show | sort -r], [0], [dnl
> +Chassis gw1
> +    hostname: localhost.localdomain

This test case is failing for me. Looks like the test suite is not
setting the hostname properly.

I am seeing the below error in testsuite.log

************
--- - 2019-11-12 23:16:17.023926966 +0530
+++ /home/nusiddiq/workspace_cpp/ovn-org/ovn-for-reviews/ovn/_gcc/tests/testsuite.dir/at-groups/204/stdout
2019-11-12 23:16:17.020998532 +0530
@@ -1,5 +1,5 @@
 Chassis gw1
-    hostname: localhost.localdomain
+    hostname: nummac.local
     Encap vxlan
     Encap geneve
         options: {csum="true"}
204. ovn-ic.at:72: 204. ovn-ic -- gateway sync (ovn-ic.at:72): FAILED
(ovn-ic.at:85)

*************

> +    Encap vxlan
> +    Encap geneve
> +        options: {csum="true"}
> +        options: {csum="true"}
> +        ip: "192.168.0.1"
> +        ip: "192.168.0.1"
> +])
> +
> +AT_CHECK([ovn_as az2 ovn-sbctl -f csv -d bare --no-headings --columns is_remote,is_interconn list chassis], [0], [dnl
> +true,false
> +])
> +
> +ovs-vsctl set open . external-ids:is-interconn=false
> +AT_CHECK([ovn_as az2 ovn-sbctl show], [0], [dnl
> +])
> +
> +ovs-vsctl set open . external-ids:is-interconn=true
> +AT_CHECK([ovn_as az2 ovn-sbctl show | grep gw1], [0], [ignore])
> +
> +OVN_CLEANUP_SBOX(gw1)
> +AT_CHECK([ovn_as az2 ovn-sbctl show], [0], [dnl
> +])
> +
> +# Test encap change
> +sim_add gw2
> +as gw2
> +ovs-vsctl add-br br-phys
> +ovn_az_attach az1 n1 br-phys 192.168.0.1
> +ovs-vsctl set open . external-ids:is-interconn=true
> +OVS_WAIT_UNTIL([ovn_as az2 ovn-sbctl show | grep "192.168.0.1"])
> +ovs-vsctl set open . external_ids:ovn-encap-ip=192.168.0.2
> +OVS_WAIT_UNTIL([ovn_as az2 ovn-sbctl show | grep "192.168.0.2"])
> +ovs-vsctl set open . external_ids:ovn-encap-type="geneve,stt"
> +OVS_WAIT_UNTIL([ovn_as az2 ovn-sbctl show | grep stt])
> +
> +OVN_CLEANUP_SBOX(gw2)
> +OVN_CLEANUP_IC([az1], [az2])
> +
> +AT_CLEANUP
> --
> 2.1.0
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
diff mbox series

Patch

diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index cf9bf96..025aad5 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -246,6 +246,152 @@  ts_run(struct ic_context *ctx)
     shash_destroy(&isb_dps);
 }
 
+/* Returns true if any information in gw and chassis is different. */
+static bool
+is_gateway_data_changed(const struct isbrec_gateway *gw,
+                   const struct sbrec_chassis *chassis)
+{
+    if (strcmp(gw->hostname, chassis->hostname)) {
+        return true;
+    }
+
+    if (gw->n_encaps != chassis->n_encaps) {
+        return true;
+    }
+
+    for (int g = 0; g < gw->n_encaps; g++) {
+
+        bool found = false;
+        const struct isbrec_encap *gw_encap = gw->encaps[g];
+        for (int s = 0; s < chassis->n_encaps; s++) {
+            const struct sbrec_encap *chassis_encap = chassis->encaps[s];
+            if (!strcmp(gw_encap->type, chassis_encap->type) &&
+                !strcmp(gw_encap->ip, chassis_encap->ip)) {
+                found = true;
+                if (!smap_equal(&gw_encap->options, &chassis_encap->options)) {
+                    return true;
+                }
+                break;
+            }
+        }
+        if (!found) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static void
+sync_isb_gw_to_sb(struct ic_context *ctx,
+                  const struct isbrec_gateway *gw,
+                  const struct sbrec_chassis *chassis)
+{
+    sbrec_chassis_set_hostname(chassis, gw->hostname);
+    sbrec_chassis_set_is_remote(chassis, true);
+
+    /* Sync encaps used by this gateway. */
+    ovs_assert(gw->n_encaps);
+    struct sbrec_encap *sb_encap;
+    struct sbrec_encap **sb_encaps =
+        xmalloc(gw->n_encaps * sizeof *sb_encaps);
+    for (int i = 0; i < gw->n_encaps; i++) {
+        sb_encap = sbrec_encap_insert(ctx->ovnsb_txn);
+        sbrec_encap_set_chassis_name(sb_encap, gw->name);
+        sbrec_encap_set_ip(sb_encap, gw->encaps[i]->ip);
+        sbrec_encap_set_type(sb_encap, gw->encaps[i]->type);
+        sbrec_encap_set_options(sb_encap, &gw->encaps[i]->options);
+        sb_encaps[i] = sb_encap;
+    }
+    sbrec_chassis_set_encaps(chassis, sb_encaps, gw->n_encaps);
+    free(sb_encaps);
+}
+
+static void
+sync_sb_gw_to_isb(struct ic_context *ctx,
+                  const struct sbrec_chassis *chassis,
+                  const struct isbrec_gateway *gw)
+{
+    isbrec_gateway_set_hostname(gw, chassis->hostname);
+
+    /* Sync encaps used by this chassis. */
+    ovs_assert(chassis->n_encaps);
+    struct isbrec_encap *isb_encap;
+    struct isbrec_encap **isb_encaps =
+        xmalloc(chassis->n_encaps * sizeof *isb_encaps);
+    for (int i = 0; i < chassis->n_encaps; i++) {
+        isb_encap = isbrec_encap_insert(ctx->ovnisb_txn);
+        isbrec_encap_set_gateway_name(isb_encap,
+                                      chassis->name);
+        isbrec_encap_set_ip(isb_encap, chassis->encaps[i]->ip);
+        isbrec_encap_set_type(isb_encap,
+                              chassis->encaps[i]->type);
+        isbrec_encap_set_options(isb_encap,
+                                 &chassis->encaps[i]->options);
+        isb_encaps[i] = isb_encap;
+    }
+    isbrec_gateway_set_encaps(gw, isb_encaps,
+                              chassis->n_encaps);
+    free(isb_encaps);
+}
+
+static void
+gateway_run(struct ic_context *ctx, const struct isbrec_availability_zone *az)
+{
+    if (!ctx->ovnisb_txn || !ctx->ovnsb_txn) {
+        return;
+    }
+
+    struct shash local_gws = SHASH_INITIALIZER(&local_gws);
+    struct shash remote_gws = SHASH_INITIALIZER(&remote_gws);
+    const struct isbrec_gateway *gw;
+    ISBREC_GATEWAY_FOR_EACH (gw, ctx->ovnisb_idl) {
+        if (gw->availability_zone == az) {
+            shash_add(&local_gws, gw->name, gw);
+        } else {
+            shash_add(&remote_gws, gw->name, gw);
+        }
+    }
+
+    const struct sbrec_chassis *chassis;
+    SBREC_CHASSIS_FOR_EACH (chassis, ctx->ovnsb_idl) {
+        if (chassis->is_interconn) {
+            gw = shash_find_and_delete(&local_gws, chassis->name);
+            if (!gw) {
+                gw = isbrec_gateway_insert(ctx->ovnisb_txn);
+                isbrec_gateway_set_availability_zone(gw, az);
+                isbrec_gateway_set_name(gw, chassis->name);
+                sync_sb_gw_to_isb(ctx, chassis, gw);
+            } else if (is_gateway_data_changed(gw, chassis)) {
+                sync_sb_gw_to_isb(ctx, chassis, gw);
+            }
+        } else if (chassis->is_remote) {
+            gw = shash_find_and_delete(&remote_gws, chassis->name);
+            if (!gw) {
+                sbrec_chassis_delete(chassis);
+            } else if (is_gateway_data_changed(gw, chassis)) {
+                sync_isb_gw_to_sb(ctx, gw, chassis);
+            }
+        }
+    }
+
+    /* Delete extra gateways from ISB for the local AZ */
+    struct shash_node *node;
+    SHASH_FOR_EACH (node, &local_gws) {
+        isbrec_gateway_delete(node->data);
+    }
+    shash_destroy(&local_gws);
+
+    /* Create SB chassis for remote gateways in ISB */
+    SHASH_FOR_EACH (node, &remote_gws) {
+        gw = node->data;
+        chassis = sbrec_chassis_insert(ctx->ovnsb_txn);
+        sbrec_chassis_set_name(chassis, gw->name);
+        sync_isb_gw_to_sb(ctx, gw, chassis);
+    }
+    shash_destroy(&remote_gws);
+}
+
 static void
 ovn_db_run(struct ic_context *ctx)
 {
@@ -257,6 +403,7 @@  ovn_db_run(struct ic_context *ctx)
     }
 
     ts_run(ctx);
+    gateway_run(ctx, az);
 }
 
 static void
diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
index 7e6644d..e5640e4 100644
--- a/tests/ovn-ic.at
+++ b/tests/ovn-ic.at
@@ -68,3 +68,59 @@  ts2
 OVN_CLEANUP_IC([az1])
 
 AT_CLEANUP
+
+AT_SETUP([ovn-ic -- gateway sync])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+
+ovn_init_ic_db
+net_add n1
+ovn_start az1
+ovn_start az2
+sim_add gw1
+as gw1
+ovs-vsctl add-br br-phys
+ovn_az_attach az1 n1 br-phys 192.168.0.1
+ovs-vsctl set open . external-ids:is-interconn=true
+
+AT_CHECK([ovn_as az2 ovn-sbctl show | sort -r], [0], [dnl
+Chassis gw1
+    hostname: localhost.localdomain
+    Encap vxlan
+    Encap geneve
+        options: {csum="true"}
+        options: {csum="true"}
+        ip: "192.168.0.1"
+        ip: "192.168.0.1"
+])
+
+AT_CHECK([ovn_as az2 ovn-sbctl -f csv -d bare --no-headings --columns is_remote,is_interconn list chassis], [0], [dnl
+true,false
+])
+
+ovs-vsctl set open . external-ids:is-interconn=false
+AT_CHECK([ovn_as az2 ovn-sbctl show], [0], [dnl
+])
+
+ovs-vsctl set open . external-ids:is-interconn=true
+AT_CHECK([ovn_as az2 ovn-sbctl show | grep gw1], [0], [ignore])
+
+OVN_CLEANUP_SBOX(gw1)
+AT_CHECK([ovn_as az2 ovn-sbctl show], [0], [dnl
+])
+
+# Test encap change
+sim_add gw2
+as gw2
+ovs-vsctl add-br br-phys
+ovn_az_attach az1 n1 br-phys 192.168.0.1
+ovs-vsctl set open . external-ids:is-interconn=true
+OVS_WAIT_UNTIL([ovn_as az2 ovn-sbctl show | grep "192.168.0.1"])
+ovs-vsctl set open . external_ids:ovn-encap-ip=192.168.0.2
+OVS_WAIT_UNTIL([ovn_as az2 ovn-sbctl show | grep "192.168.0.2"])
+ovs-vsctl set open . external_ids:ovn-encap-type="geneve,stt"
+OVS_WAIT_UNTIL([ovn_as az2 ovn-sbctl show | grep stt])
+
+OVN_CLEANUP_SBOX(gw2)
+OVN_CLEANUP_IC([az1], [az2])
+
+AT_CLEANUP