On Tue, Apr 20, 2021 at 11:57 AM Mark Michelson <[email protected]> wrote:
>
> Previous behavior of ovn-controller was to only create MAC bindings for
> the same addresses for which we would send gARPs. That is:
>
> * A logical switch has its "nat_addresses" configured.
> * That logical switch has a localnet port.
>
> This makes sense for gARPs: we only want to send gARPs for addresses
> accessible from outside of OVN, and we only want to send gARPs for
> addresses explicitly enabled by the administrator.
>
> For directly adding MAC bindings, though, this makes less sense. In the
> case where a VM or pod on the underlay network wishes to reach another
> VM or pod via a DNAT or load balancer address, an ARP was required to
> learn the MAC binding. When the information is all available in the
> database, this seems like an unnecessary step.
>
> This commit makes the following changes:
> * MAC_Binding now has a "chassis_name" column. This is used to identify
>   the chassis that added the MAC Binding IF the MAC Binding was auto-
>   generated by ovn-controller. This is also used to ensure that stale
>   bindings can be cleaned up.
> * The term "local garp" has been replaced with "chassis MAC binding".
>   Removing the word "garp" helps to remove any implication of packets
>   being transmitted. The word "chassis" precedes "MAC binding" to
>   indicate it is a MAC binding added by a chassis and with a
>   chassis_name in its records. MAC bindings with no chassis_name were
>   added dynamically due to reception of ARP/gARP packets.
> * Chassis MAC Binding code has been separated from gARP code since they
>   do not operate using the same sets of addresses.
> * Chassis MAC Bindings are added for all router_addresses on a port
>   binding. This means all NAT, Load Balancer, and router interface
>   addresses are added for routers that are residents of the chassis.
>
> Signed-off-by: Mark Michelson <[email protected]>

Hi Mark,

Please see below for just a  comment.

Thanks
Numan


> ---
>  controller/ovn-controller.c |   4 +
>  controller/pinctrl.c        | 298 +++++++++++++++++++++++++++---------
>  controller/pinctrl.h        |   1 +
>  northd/ovn-northd.c         |   2 +-
>  northd/ovn_northd.dl        |   5 +-
>  ovn-sb.ovsschema            |   5 +-
>  ovn-sb.xml                  |   7 +
>  tests/ovn-controller.at     | 179 ++++++++++++++++++++++
>  8 files changed, 427 insertions(+), 74 deletions(-)
>
> diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> index 16c8ecb21..872d68799 100644
> --- a/controller/ovn-controller.c
> +++ b/controller/ovn-controller.c
> @@ -2507,6 +2507,9 @@ main(int argc, char *argv[])
>          = ovsdb_idl_index_create2(ovnsb_idl_loop.idl,
>                                    &sbrec_fdb_col_mac,
>                                    &sbrec_fdb_col_dp_key);
> +    struct ovsdb_idl_index *sbrec_mac_binding_by_chassis
> +        = ovsdb_idl_index_create1(ovnsb_idl_loop.idl,
> +                                  &sbrec_mac_binding_col_chassis_name);
>
>      ovsdb_idl_track_add_all(ovnsb_idl_loop.idl);
>      ovsdb_idl_omit_alert(ovnsb_idl_loop.idl,
> @@ -2931,6 +2934,7 @@ main(int argc, char *argv[])
>                                      sbrec_port_binding_by_key,
>                                      sbrec_port_binding_by_name,
>                                      sbrec_mac_binding_by_lport_ip,
> +                                    sbrec_mac_binding_by_chassis,
>                                      sbrec_igmp_group,
>                                      sbrec_ip_multicast,
>                                      sbrec_fdb_by_dp_key_mac,
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index 523a45b9a..51327f370 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -205,6 +205,7 @@ static void send_garp_rarp_prepare(
>      struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
>      struct ovsdb_idl_index *sbrec_port_binding_by_name,
>      struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> +    struct ovsdb_idl_index *sbrec_mac_binding_by_chassis,
>      const struct ovsrec_bridge *,
>      const struct sbrec_chassis *,
>      const struct hmap *local_datapaths,
> @@ -3318,6 +3319,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
>              struct ovsdb_idl_index *sbrec_port_binding_by_key,
>              struct ovsdb_idl_index *sbrec_port_binding_by_name,
>              struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> +            struct ovsdb_idl_index *sbrec_mac_binding_by_chassis,
>              struct ovsdb_idl_index *sbrec_igmp_groups,
>              struct ovsdb_idl_index *sbrec_ip_multicast_opts,
>              struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac,
> @@ -3339,7 +3341,8 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
>                             sbrec_port_binding_by_key, chassis);
>      send_garp_rarp_prepare(ovnsb_idl_txn, sbrec_port_binding_by_datapath,
>                             sbrec_port_binding_by_name,
> -                           sbrec_mac_binding_by_lport_ip, br_int, chassis,
> +                           sbrec_mac_binding_by_lport_ip,
> +                           sbrec_mac_binding_by_chassis, br_int, chassis,
>                             local_datapaths, active_tunnels);
>      prepare_ipv6_ras(local_datapaths);
>      prepare_ipv6_prefixd(ovnsb_idl_txn, sbrec_port_binding_by_name,
> @@ -4008,7 +4011,8 @@ mac_binding_add_to_sb(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>                        const char *logical_port,
>                        const struct sbrec_datapath_binding *dp,
>                        struct eth_addr ea, const char *ip,
> -                      bool update_only)
> +                      bool update_only,
> +                      const struct sbrec_chassis *chassis)
>  {
>      /* Convert ethernet argument to string form for database. */
>      char mac_string[ETH_ADDR_STRLEN + 1];
> @@ -4025,49 +4029,20 @@ mac_binding_add_to_sb(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>          sbrec_mac_binding_set_ip(b, ip);
>          sbrec_mac_binding_set_mac(b, mac_string);
>          sbrec_mac_binding_set_datapath(b, dp);
> -    } else if (strcmp(b->mac, mac_string)) {
> -        sbrec_mac_binding_set_mac(b, mac_string);
> -    }
> -}
> -
> -/* Simulate the effect of a GARP on local datapaths, i.e., create 
> MAC_Bindings
> - * on peer router datapaths.
> - */
> -static void
> -send_garp_locally(struct ovsdb_idl_txn *ovnsb_idl_txn,
> -                  struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> -                  const struct hmap *local_datapaths,
> -                  const struct sbrec_port_binding *in_pb,
> -                  struct eth_addr ea, ovs_be32 ip)
> -{
> -    if (!ovnsb_idl_txn) {
> -        return;
> -    }
> -
> -    const struct local_datapath *ldp =
> -        get_local_datapath(local_datapaths, in_pb->datapath->tunnel_key);
> -
> -    ovs_assert(ldp);
> -    for (size_t i = 0; i < ldp->n_peer_ports; i++) {
> -        const struct sbrec_port_binding *local = ldp->peer_ports[i].local;
> -        const struct sbrec_port_binding *remote = ldp->peer_ports[i].remote;
> -
> -        /* Skip "ingress" port. */
> -        if (local == in_pb) {
> -            continue;
> +        if (chassis) {
> +            sbrec_mac_binding_set_chassis_name(b, chassis->name);
> +        }
> +    } else {
> +        if (strcmp(b->mac, mac_string)) {
> +            sbrec_mac_binding_set_mac(b, mac_string);
> +        }
> +        if (b->chassis_name[0]) {
> +            if (chassis && strcmp(b->chassis_name, chassis->name)) {
> +                sbrec_mac_binding_set_chassis_name(b, chassis->name);
> +            } else if (!chassis) {
> +                sbrec_mac_binding_set_chassis_name(b, "");
> +            }
>          }
> -
> -        bool update_only = !smap_get_bool(&remote->datapath->external_ids,
> -                                          "always_learn_from_arp_request",
> -                                          true);
> -
> -        struct ds ip_s = DS_EMPTY_INITIALIZER;
> -
> -        ip_format_masked(ip, OVS_BE32_MAX, &ip_s);
> -        mac_binding_add_to_sb(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
> -                              remote->logical_port, remote->datapath,
> -                              ea, ds_cstr(&ip_s), update_only);
> -        ds_destroy(&ip_s);
>      }
>  }
>
> @@ -4099,7 +4074,7 @@ run_put_mac_binding(struct ovsdb_idl_txn *ovnsb_idl_txn,
>      ipv6_format_mapped(&mb->ip, &ip_s);
>      mac_binding_add_to_sb(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
>                            pb->logical_port, pb->datapath, mb->mac,
> -                          ds_cstr(&ip_s), false);
> +                          ds_cstr(&ip_s), false, NULL);
>      ds_destroy(&ip_s);
>  }
>
> @@ -4233,9 +4208,7 @@ add_garp_rarp(const char *name, const struct eth_addr 
> ea, ovs_be32 ip,
>
>  /* Add or update a vif for which GARPs need to be announced. */
>  static void
> -send_garp_rarp_update(struct ovsdb_idl_txn *ovnsb_idl_txn,
> -                      struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> -                      const struct hmap *local_datapaths,
> +send_garp_rarp_update(const struct hmap *local_datapaths,
>                        const struct sbrec_port_binding *binding_rec,
>                        struct shash *nat_addresses)
>  {
> @@ -4246,6 +4219,13 @@ send_garp_rarp_update(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>          return;
>      }
>
> +    struct local_datapath *ldp = get_local_datapath(
> +            local_datapaths, binding_rec->datapath->tunnel_key);
> +    ovs_assert(ldp);
> +    if (!ldp->localnet_port) {
> +        return;
> +    }
> +
>      /* Update GARP for NAT IP if it exists.  Consider port bindings with type
>       * "l3gateway" for logical switch ports attached to gateway routers, and
>       * port bindings with type "patch" for logical switch ports attached to
> @@ -4268,11 +4248,6 @@ send_garp_rarp_update(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>                                    laddrs->ipv4_addrs[i].addr,
>                                    binding_rec->datapath->tunnel_key,
>                                    binding_rec->tunnel_key);
> -                    send_garp_locally(ovnsb_idl_txn,
> -                                      sbrec_mac_binding_by_lport_ip,
> -                                      local_datapaths, binding_rec, 
> laddrs->ea,
> -                                      laddrs->ipv4_addrs[i].addr);
> -
>                  }
>                  free(name);
>              }
> @@ -4308,10 +4283,6 @@ send_garp_rarp_update(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>                        laddrs.ea, ip,
>                        binding_rec->datapath->tunnel_key,
>                        binding_rec->tunnel_key);
> -        if (ip) {
> -            send_garp_locally(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
> -                              local_datapaths, binding_rec, laddrs.ea, ip);
> -        }
>
>          destroy_lport_addresses(&laddrs);
>          break;
> @@ -5424,10 +5395,6 @@ get_localnet_vifs_l3gwports(
>      HMAP_FOR_EACH (ld, hmap_node, local_datapaths) {
>          const struct sbrec_port_binding *pb;
>
> -        if (!ld->localnet_port) {
> -            continue;
> -        }
> -
>          /* Get l3gw ports.  Consider port bindings with type "l3gateway"
>           * that connect to gateway routers (if local), and consider port
>           * bindings of type "patch" since they might connect to
> @@ -5551,7 +5518,8 @@ get_nat_addresses_and_keys(struct ovsdb_idl_index 
> *sbrec_port_binding_by_name,
>                             struct sset *local_l3gw_ports,
>                             const struct sbrec_chassis *chassis,
>                             const struct sset *active_tunnels,
> -                           struct shash *nat_addresses)
> +                           struct shash *garp_addresses,
> +                           struct shash *router_addresses)
>  {
>      const char *gw_port;
>      SSET_FOR_EACH(gw_port, local_l3gw_ports) {
> @@ -5568,7 +5536,7 @@ get_nat_addresses_and_keys(struct ovsdb_idl_index 
> *sbrec_port_binding_by_name,
>                                       pb->nat_addresses[i], pb,
>                                       nat_address_keys, chassis,
>                                       active_tunnels,
> -                                     nat_addresses);
> +                                     garp_addresses);
>              }
>          } else {
>              /* Continue to support options:nat-addresses for version
> @@ -5580,9 +5548,16 @@ get_nat_addresses_and_keys(struct ovsdb_idl_index 
> *sbrec_port_binding_by_name,
>                                       nat_addresses_options, pb,
>                                       nat_address_keys, chassis,
>                                       active_tunnels,
> -                                     nat_addresses);
> +                                     garp_addresses);
>              }
>          }
> +
> +        for (int i = 0; i < pb->n_router_addresses; i++) {
s/int/size_t

> +            consider_nat_address(sbrec_port_binding_by_name,
> +                                 pb->router_addresses[i], pb,
> +                                 nat_address_keys, chassis,
> +                                 active_tunnels, router_addresses);
> +        }
>      }
>  }
>
> @@ -5618,6 +5593,165 @@ send_garp_rarp_run(struct rconn *swconn, long long 
> int *send_garp_rarp_time)
>      }
>  }
>
> +struct chassis_mac_binding {
> +    struct hmap_node hmap_node;
> +    const struct sbrec_mac_binding *binding;
> +    uint32_t hash;
> +};
> +
> +static uint32_t
> +chassis_mac_binding_hash_(const char *ip, const char *logical_port)
> +{
> +    return hash_string(ip, hash_string(logical_port, 0));
> +}
> +
> +static uint32_t
> +chassis_mac_binding_hash(const struct sbrec_mac_binding *binding)
> +{
> +    return chassis_mac_binding_hash_(binding->ip, binding->logical_port);
> +}
> +
> +static struct chassis_mac_binding *
> +chassis_mac_binding_alloc(const struct sbrec_mac_binding *binding)
> +{
> +    struct chassis_mac_binding *cmb = xmalloc(sizeof *cmb);
> +    cmb->binding = binding;
> +    cmb->hash = chassis_mac_binding_hash(binding);
> +    return cmb;
> +}
> +
> +static void
> +chassis_mac_binding_remove(struct hmap *chassis_mac_bindings,
> +                           const char *ip, const char *logical_port)
> +{
> +    uint32_t hash = chassis_mac_binding_hash_(ip, logical_port);
> +    struct chassis_mac_binding *cmb;
> +    HMAP_FOR_EACH_WITH_HASH (cmb, hmap_node, hash, chassis_mac_bindings) {
> +        if (!strcmp(cmb->binding->ip, ip)
> +            && !strcmp(cmb->binding->logical_port, logical_port)) {
> +            hmap_remove(chassis_mac_bindings, &cmb->hmap_node);
> +            free(cmb);
> +            break;
> +        }
> +    }
> +}
> +
> +static void
> +delete_old_chassis_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn,
> +                                struct hmap *chassis_mac_bindings)
> +{
> +    if (!ovnsb_idl_txn) {
> +        return;
> +    }
> +    struct chassis_mac_binding *cmb;
> +    HMAP_FOR_EACH_POP (cmb, hmap_node, chassis_mac_bindings) {
> +        sbrec_mac_binding_delete(cmb->binding);
> +        free(cmb);
> +    }
> +}
> +
> +static void
> +get_chassis_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn,
> +                         struct ovsdb_idl_index 
> *sbrec_mac_binding_by_chassis,
> +                         const struct sbrec_chassis *chassis,
> +                         struct hmap *chassis_mac_bindings)
> +{
> +    if (!ovnsb_idl_txn) {
> +        return;
> +    }
> +    const struct sbrec_mac_binding *mac_binding;
> +
> +    struct sbrec_mac_binding *mb_row = sbrec_mac_binding_index_init_row(
> +        sbrec_mac_binding_by_chassis);
> +    sbrec_mac_binding_index_set_chassis_name(mb_row, chassis->name);
> +
> +    SBREC_MAC_BINDING_FOR_EACH_EQUAL (mac_binding, mb_row,
> +                                      sbrec_mac_binding_by_chassis) {
> +        struct chassis_mac_binding *ch_binding =
> +            chassis_mac_binding_alloc(mac_binding);
> +        hmap_insert(chassis_mac_bindings, &ch_binding->hmap_node, 
> ch_binding->hash);
> +    }
> +    sbrec_mac_binding_index_destroy_row(mb_row);
> +}
> +
> +/* Simulate the effect of a GARP on local datapaths, i.e., create 
> MAC_Bindings
> + * on peer router datapaths.
> + */
> +static void
> +install_chassis_mac_binding(struct ovsdb_idl_txn *ovnsb_idl_txn,
> +                            struct ovsdb_idl_index 
> *sbrec_mac_binding_by_lport_ip,
> +                            const struct local_datapath *ldp,
> +                            const struct sbrec_port_binding *in_pb,
> +                            struct eth_addr ea, ovs_be32 ip,
> +                            const struct sbrec_chassis *chassis,
> +                            struct hmap *old_chassis_mac_bindings)
> +{
> +    ovs_assert(ovnsb_idl_txn && ldp);
> +
> +    struct ds ip_s = DS_EMPTY_INITIALIZER;
> +
> +    ip_format_masked(ip, OVS_BE32_MAX, &ip_s);
> +    for (size_t i = 0; i < ldp->n_peer_ports; i++) {
> +        const struct sbrec_port_binding *local = ldp->peer_ports[i].local;
> +        const struct sbrec_port_binding *remote = ldp->peer_ports[i].remote;
> +
> +        /* Skip "ingress" port. */
> +        if (local == in_pb) {
> +            continue;
> +        }
> +
> +        bool update_only = !smap_get_bool(&remote->datapath->external_ids,
> +                                          "always_learn_from_arp_request",
> +                                          true);
> +
> +        mac_binding_add_to_sb(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
> +                              remote->logical_port, remote->datapath,
> +                              ea, ds_cstr(&ip_s), update_only, chassis);
> +
> +        chassis_mac_binding_remove(old_chassis_mac_bindings, ds_cstr(&ip_s),
> +                                   remote->logical_port);
> +
> +    }
> +    ds_destroy(&ip_s);
> +}
> +
> +static void
> +install_chassis_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn,
> +                             struct ovsdb_idl_index 
> *sbrec_mac_binding_by_lport_ip,
> +                             const struct hmap *local_datapaths,
> +                             const struct sbrec_port_binding *in_pb,
> +                             struct shash *router_addresses,
> +                             const struct sbrec_chassis *chassis,
> +                             struct hmap *old_chassis_mac_bindings)
> +{
> +    if (!ovnsb_idl_txn) {
> +        return;
> +    }
> +
> +    if (strcmp(in_pb->type, "l3gateway")
> +        && strcmp(in_pb->type, "patch")) {
> +        return;
> +    }
> +
> +    const struct local_datapath *ldp =
> +        get_local_datapath(local_datapaths, in_pb->datapath->tunnel_key);
> +
> +    struct lport_addresses *laddrs = NULL;
> +    while ((laddrs = shash_find_and_delete(router_addresses,
> +                                           in_pb->logical_port))) {
> +        int i;
> +        for (i = 0; i < laddrs->n_ipv4_addrs; i++) {
> +            install_chassis_mac_binding(ovnsb_idl_txn,
> +                                        sbrec_mac_binding_by_lport_ip,
> +                                        ldp, in_pb, laddrs->ea,
> +                                        laddrs->ipv4_addrs[i].addr,
> +                                        chassis, old_chassis_mac_bindings);
> +        }
> +        destroy_lport_addresses(laddrs);
> +        free(laddrs);
> +    }
> +}
> +
>  /* Called by pinctrl_run(). Runs with in the main ovn-controller
>   * thread context. */
>  static void
> @@ -5625,6 +5759,7 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>                         struct ovsdb_idl_index 
> *sbrec_port_binding_by_datapath,
>                         struct ovsdb_idl_index *sbrec_port_binding_by_name,
>                         struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> +                       struct ovsdb_idl_index *sbrec_mac_binding_by_chassis,
>                         const struct ovsrec_bridge *br_int,
>                         const struct sbrec_chassis *chassis,
>                         const struct hmap *local_datapaths,
> @@ -5635,8 +5770,15 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>      struct sset local_l3gw_ports = SSET_INITIALIZER(&local_l3gw_ports);
>      struct sset nat_ip_keys = SSET_INITIALIZER(&nat_ip_keys);
>      struct shash nat_addresses;
> +    struct shash router_addresses;
> +    struct hmap old_chassis_mac_bindings;
>
>      shash_init(&nat_addresses);
> +    shash_init(&router_addresses);
> +    hmap_init(&old_chassis_mac_bindings);
> +
> +    get_chassis_mac_bindings(ovnsb_idl_txn, sbrec_mac_binding_by_chassis,
> +                             chassis, &old_chassis_mac_bindings);
>
>      get_localnet_vifs_l3gwports(sbrec_port_binding_by_datapath,
>                                  sbrec_port_binding_by_name,
> @@ -5646,7 +5788,8 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>      get_nat_addresses_and_keys(sbrec_port_binding_by_name,
>                                 &nat_ip_keys, &local_l3gw_ports,
>                                 chassis, active_tunnels,
> -                               &nat_addresses);
> +                               &nat_addresses,
> +                               &router_addresses);
>      /* For deleted ports and deleted nat ips, remove from
>       * send_garp_rarp_data. */
>      struct shash_node *iter, *next;
> @@ -5663,8 +5806,11 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>          const struct sbrec_port_binding *pb = lport_lookup_by_name(
>              sbrec_port_binding_by_name, iface_id);
>          if (pb) {
> -            send_garp_rarp_update(ovnsb_idl_txn, 
> sbrec_mac_binding_by_lport_ip,
> -                                  local_datapaths, pb, &nat_addresses);
> +            send_garp_rarp_update(local_datapaths, pb, &nat_addresses);
> +            install_chassis_mac_bindings(ovnsb_idl_txn, 
> sbrec_mac_binding_by_lport_ip,
> +                                         local_datapaths, pb,
> +                                         &router_addresses, chassis,
> +                                         &old_chassis_mac_bindings);
>          }
>      }
>
> @@ -5674,11 +5820,17 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>          const struct sbrec_port_binding *pb
>              = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port);
>          if (pb) {
> -            send_garp_rarp_update(ovnsb_idl_txn, 
> sbrec_mac_binding_by_lport_ip,
> -                                  local_datapaths, pb, &nat_addresses);
> +            send_garp_rarp_update(local_datapaths, pb, &nat_addresses);
> +            install_chassis_mac_bindings(ovnsb_idl_txn, 
> sbrec_mac_binding_by_lport_ip,
> +                                         local_datapaths, pb,
> +                                         &router_addresses, chassis,
> +                                         &old_chassis_mac_bindings);
>          }
>      }
>
> +    delete_old_chassis_mac_bindings(ovnsb_idl_txn, 
> &old_chassis_mac_bindings);
> +    hmap_destroy(&old_chassis_mac_bindings);
> +
>      /* pinctrl_handler thread will send the GARPs. */
>
>      sset_destroy(&localnet_vifs);
> @@ -5692,6 +5844,14 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>      }
>      shash_destroy(&nat_addresses);
>
> +    SHASH_FOR_EACH_SAFE (iter, next, &router_addresses) {
> +        struct lport_addresses *laddrs = iter->data;
> +        destroy_lport_addresses(laddrs);
> +        shash_delete(&router_addresses, iter);
> +        free(laddrs);
> +    }
> +    shash_destroy(&router_addresses);
> +
>      sset_destroy(&nat_ip_keys);
>  }
>
> diff --git a/controller/pinctrl.h b/controller/pinctrl.h
> index cc0a51984..5d4f32b4a 100644
> --- a/controller/pinctrl.h
> +++ b/controller/pinctrl.h
> @@ -40,6 +40,7 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
>                   struct ovsdb_idl_index *sbrec_port_binding_by_key,
>                   struct ovsdb_idl_index *sbrec_port_binding_by_name,
>                   struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> +                 struct ovsdb_idl_index *sbrec_mac_binding_by_chassis,
>                   struct ovsdb_idl_index *sbrec_igmp_groups,
>                   struct ovsdb_idl_index *sbrec_ip_multicast_opts,
>                   struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac,
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index 78ac696a5..d36a3c29b 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -13696,7 +13696,7 @@ static const char *rbac_port_binding_update[] =
>  static const char *rbac_mac_binding_auth[] =
>      {""};
>  static const char *rbac_mac_binding_update[] =
> -    {"logical_port", "ip", "mac", "datapath"};
> +    {"logical_port", "ip", "mac", "datapath", "chassis_name"};
>
>  static const char *rbac_svc_monitor_auth[] =
>      {""};
> diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl
> index 2be6591e9..089947516 100644
> --- a/northd/ovn_northd.dl
> +++ b/northd/ovn_northd.dl
> @@ -955,7 +955,8 @@ sb::Out_MAC_Binding (._uuid        = mb._uuid,
>                      .logical_port = mb.logical_port,
>                      .ip           = mb.ip,
>                      .mac          = mb.mac,
> -                    .datapath     = mb.datapath) :-
> +                    .datapath     = mb.datapath,
> +                    .chassis_name = mb.chassis_name) :-
>      sb::MAC_Binding[mb],
>      sb::Out_Port_Binding(.logical_port = mb.logical_port),
>      sb::Out_Datapath_Binding(._uuid = mb.datapath).
> @@ -1312,7 +1313,7 @@ sb::Out_RBAC_Permission (
>      .table          = "MAC_Binding",
>      .authorization  = set_singleton(""),
>      .insert_delete  = true,
> -    .update         = ["logical_port", "ip", "mac", "datapath"].to_set()
> +    .update         = ["logical_port", "ip", "mac", "datapath", 
> "chassis_name"].to_set()
>  ).
>
>  sb::Out_RBAC_Permission (
> diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema
> index b879e6228..182a95528 100644
> --- a/ovn-sb.ovsschema
> +++ b/ovn-sb.ovsschema
> @@ -1,7 +1,7 @@
>  {
>      "name": "OVN_Southbound",
>      "version": "20.17.0",
> -    "cksum": "367711378 26723",
> +    "cksum": "394417570 26775",
>      "tables": {
>          "SB_Global": {
>              "columns": {
> @@ -241,7 +241,8 @@
>                  "ip": {"type": "string"},
>                  "mac": {"type": "string"},
>                  "datapath": {"type": {"key": {"type": "uuid",
> -                                              "refTable": 
> "Datapath_Binding"}}}},
> +                                              "refTable": 
> "Datapath_Binding"}}},
> +                "chassis_name": {"type": "string"}},
>              "indexes": [["logical_port", "ip"]],
>              "isRoot": true},
>          "DHCP_Options": {
> diff --git a/ovn-sb.xml b/ovn-sb.xml
> index 610dca17c..7648a9e78 100644
> --- a/ovn-sb.xml
> +++ b/ovn-sb.xml
> @@ -3345,6 +3345,13 @@ tcp.flags = RST;
>      <column name="datapath">
>        The logical datapath to which the logical port belongs.
>      </column>
> +    <column name="chassis_name">
> +      This column indicates the chassis on which the binding was added. This
> +      column is only filled in when ovn-controller generates the MAC binding
> +      internally. MAC bindings learned due to ARP requests will not have this
> +      column set. This is used internally by ovn-controller to ensure that
> +      defunct bindings are removed.
> +    </column>
>    </table>
>
>    <table name="DHCP_Options" title="DHCP Options supported by native OVN 
> DHCP">
> diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
> index d1d758c49..b37e135f9 100644
> --- a/tests/ovn-controller.at
> +++ b/tests/ovn-controller.at
> @@ -549,3 +549,182 @@ done
>
>  OVN_CLEANUP([hv1])
>  AT_CLEANUP
> +
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([ovn -- MAC bindings from router addresses])
> +ovn_start
> +
> +net_add n1
> +for i in 1 2; do
> +    sim_add hv$i
> +    as hv$i
> +    ovs-vsctl add-br br-phys
> +    ovn_attach n1 br-phys 192.168.$i.1
> +done
> +
> +AS_BOX([Setting up the logical network])
> +# This test ties in heavily with the ovn-northd "Router Address
> +# Propagation" test. That test ensures that Port_Binding
> +# router_addresses are filled in as expected based on the logical
> +# network configuration.
> +#
> +# This test focuses on ensuring that router_addresses get
> +# converted to the expected MAC_Bindings, specifically with regards
> +# to ensuring they are created based on is_chassis_resident
> +# restrictions. Therefore, it is not necessary to ensure that an
> +# exhaustive set of logical network configurations is attempted for
> +# this test.
> +
> +check ovn-nbctl ls-add sw
> +
> +check ovn-nbctl lr-add ro1
> +check ovn-nbctl lrp-add ro1 ro1-sw 00:00:00:00:00:01 10.0.0.1/24
> +check ovn-nbctl lsp-add sw sw-ro1
> +
> +check ovn-nbctl lr-add ro2
> +check ovn-nbctl lrp-add ro2 ro2-sw 00:00:00:00:00:02 20.0.0.1/24
> +check ovn-nbctl --wait=sb lsp-add sw sw-ro2
> +
> +check ovn-nbctl ls-add ls1
> +check ovn-nbctl lsp-add ls1 vm1
> +check ovn-nbctl lsp-set-addresses vm1 "00:00:00:00:01:02 172.16.1.2"
> +check ovn-nbctl lrp-add ro1 ro1-ls1 00:00:00:00:01:01 172.16.1.1/24
> +check ovn-nbctl lsp-add ls1 ls1-ro1
> +check ovn-nbctl lsp-set-type ls1-ro1 router
> +check ovn-nbctl lsp-set-addresses ls1-ro1 router
> +check ovn-nbctl lsp-set-options ls1-ro1 router-port=ro1-ls1
> +
> +check ovn-nbctl ls-add ls2
> +check ovn-nbctl lsp-add ls2 vm2
> +check ovn-nbctl lsp-set-addresses vm2 "00:00:00:00:02:02 172.16.2.2"
> +check ovn-nbctl lrp-add ro2 ro2-ls2 00:00:00:00:02:01 172.16.2.1/24
> +check ovn-nbctl lsp-add ls2 ls2-ro2
> +check ovn-nbctl lsp-set-type ls2-ro2 router
> +check ovn-nbctl lsp-set-addresses ls2-ro2 router
> +check ovn-nbctl --wait=hv lsp-set-options ls2-ro2 router-port=ro2-ls2
> +
> +as hv1
> +check ovs-vsctl add-port br-int vm1 -- set Interface vm1 
> external_ids:iface-id=vm1
> +as hv2
> +check ovs-vsctl add-port br-int vm2 -- set Interface vm2 
> external_ids:iface-id=vm2
> +
> +AS_BOX([Checking that no router addresses results in no chassis-specific MAC 
> Bindings])
> +
> +check_row_count MAC_Binding 0 chassis_name=hv1
> +check_row_count MAC_Binding 0 chassis_name=hv2
> +
> +AS_BOX([Checking that connecting routers results in no chassis-specific MAC 
> Bindings])
> +
> +check ovn-nbctl lsp-set-type sw-ro1 router
> +check ovn-nbctl lsp-set-addresses sw-ro1 router
> +check ovn-nbctl lsp-set-options sw-ro1 router-port=ro1-sw
> +
> +check ovn-nbctl lsp-set-type sw-ro2 router
> +check ovn-nbctl lsp-set-addresses sw-ro2 router
> +check ovn-nbctl --wait=hv lsp-set-options sw-ro2 router-port=ro2-sw
> +
> +check_row_count MAC_Binding 0 chassis_name=hv1
> +check_row_count MAC_Binding 0 chassis_name=hv2
> +
> +AS_BOX([Checking that l3dgw routers have chassis-specific MAC Bindings])
> +
> +check ovn-nbctl lrp-set-gateway-chassis ro1-sw hv1 100
> +check ovn-nbctl --wait=hv lrp-set-gateway-chassis ro2-sw hv2 100
> +
> +check_row_count MAC_Binding 1 chassis_name=hv1
> +check_row_count MAC_Binding 1 chassis_name=hv2
> +
> +check_column "10.0.0.1" MAC_Binding ip chassis_name=hv1
> +check_column "00:00:00:00:00:01" MAC_Binding mac chassis_name=hv1
> +check_column "ro2-sw" MAC_Binding logical_port chassis_name=hv1
> +
> +check_column "20.0.0.1" MAC_Binding ip chassis_name=hv2
> +check_column "00:00:00:00:00:02" MAC_Binding mac chassis_name=hv2
> +check_column "ro1-sw" MAC_Binding logical_port chassis_name=hv2
> +
> +AS_BOX([Checking that NAT addresses result in chassis-specific MAC Bindings])
> +
> +check ovn-nbctl lr-nat-add ro1 dnat 10.0.0.100 172.16.1.100
> +check ovn-nbctl --wait=hv lr-nat-add ro1 snat 10.0.0.200 172.16.1.200/30
> +
> +# hv1 installs MAC bindings for the ro1's router address and two NAT 
> addresses
> +check_row_count MAC_Binding 3 chassis_name=hv1
> +# hv2 only installs MAC bindings for ro2's router address
> +check_row_count MAC_Binding 1 chassis_name=hv2
> +
> +check_column "10.0.0.1 10.0.0.100 10.0.0.200" MAC_Binding ip chassis_name=hv1
> +check_column "00:00:00:00:00:01 00:00:00:00:00:01 00:00:00:00:00:01" 
> MAC_Binding mac chassis_name=hv1
> +check_column "ro2-sw ro2-sw ro2-sw" MAC_Binding logical_port chassis_name=hv1
> +
> +check_column "20.0.0.1" MAC_Binding ip chassis_name=hv2
> +check_column "00:00:00:00:00:02" MAC_Binding mac chassis_name=hv2
> +check_column "ro1-sw" MAC_Binding logical_port chassis_name=hv2
> +
> +AS_BOX([Checking that changing which router has NAT addresses results in 
> correct MAC Bindings])
> +
> +check ovn-nbctl lr-nat-del ro1
> +
> +check ovn-nbctl lr-nat-add ro2 dnat 20.0.0.100 172.16.2.100
> +check ovn-nbctl --wait=hv lr-nat-add ro2 snat 20.0.0.200 172.16.2.200/30
> +
> +# hv1 installs MAC bindings for ro1's router address
> +check_row_count MAC_Binding 1 chassis_name=hv1
> +# hv2 installs MAC bindings for ro2's router address and two NAT addresses
> +check_row_count MAC_Binding 3 chassis_name=hv2
> +
> +check_column "10.0.0.1" MAC_Binding ip chassis_name=hv1
> +check_column "00:00:00:00:00:01" MAC_Binding mac chassis_name=hv1
> +check_column "ro2-sw" MAC_Binding logical_port chassis_name=hv1
> +
> +check_column "20.0.0.1 20.0.0.100 20.0.0.200" MAC_Binding ip chassis_name=hv2
> +check_column "00:00:00:00:00:02 00:00:00:00:00:02 00:00:00:00:00:02" 
> MAC_Binding mac chassis_name=hv2
> +check_column "ro1-sw ro1-sw ro1-sw" MAC_Binding logical_port chassis_name=hv2
> +
> +AS_BOX([Checking that Floating IP NAT address configured on router results 
> in MAC Binding])
> +
> +check ovn-nbctl lr-nat-del ro2
> +
> +check ovn-nbctl --wait=hv lr-nat-add ro1 dnat_and_snat 10.0.0.100 
> 172.16.1.100 vm1 00:00:00:00:00:01
> +
> +# HV1 will have MAC bindings for the router address and the Floating IP NAT 
> since vm1 is bound on hv1
> +check_row_count MAC_Binding 2 chassis_name=hv1
> +check_row_count MAC_Binding 1 chassis_name=hv2
> +
> +check_column "10.0.0.1 10.0.0.100" MAC_Binding ip chassis_name=hv1
> +check_column "00:00:00:00:00:01 00:00:00:00:00:01" MAC_Binding mac 
> chassis_name=hv1
> +check_column "ro2-sw ro2-sw" MAC_Binding logical_port chassis_name=hv1
> +
> +check_column "20.0.0.1" MAC_Binding ip chassis_name=hv2
> +check_column "00:00:00:00:00:02" MAC_Binding mac chassis_name=hv2
> +check_column "ro1-sw" MAC_Binding logical_port chassis_name=hv2
> +
> +AS_BOX([Checking that un-binding vm results in removal of Floating IP MAC 
> Binding])
> +
> +as hv1
> +check ovs-vsctl del-port br-int vm1
> +
> +# This will be exactly as if no NATs were configured.
> +# Use wait_row_count instead of check_row_count here since
> +# we don't have an equivalent to --wait=hv in ovs-vsctl.
> +wait_row_count MAC_Binding 1 chassis_name=hv1
> +check_row_count MAC_Binding 1 chassis_name=hv2
> +
> +check_column "10.0.0.1" MAC_Binding ip chassis_name=hv1
> +check_column "00:00:00:00:00:01" MAC_Binding mac chassis_name=hv1
> +check_column "ro2-sw" MAC_Binding logical_port chassis_name=hv1
> +
> +check_column "20.0.0.1" MAC_Binding ip chassis_name=hv2
> +check_column "00:00:00:00:00:02" MAC_Binding mac chassis_name=hv2
> +check_column "ro1-sw" MAC_Binding logical_port chassis_name=hv2
> +
> +AS_BOX([Ensure that disconnecting routers results in removal of all MAC 
> Bindings])
> +
> +check ovn-nbctl clear logical_switch_port sw-ro1 options
> +check ovn-nbctl --wait=hv clear logical_switch_port sw-ro2 options
> +
> +check_row_count MAC_Binding 0 chassis_name=hv1
> +check_row_count MAC_Binding 0 chassis_name=hv2
> +
> +OVN_CLEANUP([hv1],[hv2])
> +AT_CLEANUP
> +])
> --
> 2.29.2
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to