On Wed, Aug 6, 2025 at 12:54 PM Dumitru Ceara <dce...@redhat.com> wrote:

> On 7/25/25 8:03 AM, Ales Musil wrote:
> > Create FDB structure and flows based on the FDB learned from the
> > netlink neighbor table. This is required to make the traffic unicast.
> > We can do the mapping between binding and remote VTEP FDB by
> > populating the remote FDB side table.
> >
> > The flows in that table will be utilized in future commit.
> >
> > Signed-off-by: Ales Musil <amu...@redhat.com>
> > ---
>
> Hi Ales,
>
> Just a minor nit/note below.  Otherwise this looks OK to me.
>
> >  controller/automake.mk              |   2 +
> >  controller/evpn-fdb.c               | 151 ++++++++++++++++++++++++++++
> >  controller/evpn-fdb.h               |  59 +++++++++++
> >  controller/lflow.h                  |   1 +
> >  controller/neighbor-exchange-stub.c |   5 +
> >  controller/neighbor-exchange.c      |  77 +++++++++++++-
> >  controller/neighbor-exchange.h      |  13 +++
> >  controller/ovn-controller.c         | 122 +++++++++++++++++++++-
> >  controller/physical.c               |  48 +++++++++
> >  controller/physical.h               |   4 +
> >  tests/ovn-macros.at                 |   1 +
> >  11 files changed, 481 insertions(+), 2 deletions(-)
> >  create mode 100644 controller/evpn-fdb.c
> >  create mode 100644 controller/evpn-fdb.h
> >
> > diff --git a/controller/automake.mk b/controller/automake.mk
> > index 8d94fb646..d53d932c1 100644
> > --- a/controller/automake.mk
> > +++ b/controller/automake.mk
> > @@ -12,6 +12,8 @@ controller_ovn_controller_SOURCES = \
> >       controller/encaps.h \
> >       controller/evpn-binding.c \
> >       controller/evpn-binding.h \
> > +     controller/evpn-fdb.c \
> > +     controller/evpn-fdb.h \
> >       controller/ha-chassis.c \
> >       controller/ha-chassis.h \
> >       controller/if-status.c \
> > diff --git a/controller/evpn-fdb.c b/controller/evpn-fdb.c
> > new file mode 100644
> > index 000000000..02318cde2
> > --- /dev/null
> > +++ b/controller/evpn-fdb.c
> > @@ -0,0 +1,151 @@
> > +/* Copyright (c) 2025, Red Hat, Inc.
> > + *
> > + * Licensed under the Apache License, Version 2.0 (the "License");
> > + * you may not use this file except in compliance with the License.
> > + * You may obtain a copy of the License at:
> > + *
> > + *     http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing, software
> > + * distributed under the License is distributed on an "AS IS" BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> > + * See the License for the specific language governing permissions and
> > + * limitations under the License.
> > + */
> > +
> > +#include <config.h>
> > +
> > +#include "evpn-binding.h"
> > +#include "neighbor-exchange.h"
> > +#include "openvswitch/dynamic-string.h"
> > +#include "openvswitch/vlog.h"
> > +#include "packets.h"
> > +#include "unixctl.h"
> > +
> > +#include "evpn-fdb.h"
> > +
> > +VLOG_DEFINE_THIS_MODULE(evpn_fdb);
> > +
> > +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> > +
> > +static struct evpn_fdb *evpn_fdb_add(struct hmap *evpn_fdbs, struct
> eth_addr);
> > +static struct evpn_fdb *evpn_fdb_find(const struct hmap *evpn_fdbs,
> > +                                      struct eth_addr);
> > +
> > +void
> > +evpn_fdb_run(const struct evpn_fdb_ctx_in *f_ctx_in,
> > +             struct evpn_fdb_ctx_out *f_ctx_out)
> > +{
> > +    struct hmapx stale_fdbs = HMAPX_INITIALIZER(&stale_fdbs);
> > +
> > +    struct evpn_fdb *fdb;
> > +    HMAP_FOR_EACH (fdb, hmap_node, f_ctx_out->fdbs) {
> > +        hmapx_add(&stale_fdbs, fdb);
> > +    }
> > +
> > +    const struct evpn_static_fdb *static_fdb;
> > +    HMAP_FOR_EACH (static_fdb, hmap_node, f_ctx_in->static_fdbs) {
> > +        const struct evpn_binding *binding =
> > +            evpn_binding_find(f_ctx_in->bindings, &static_fdb->ip,
> > +                              static_fdb->vni);
> > +        if (!binding) {
> > +            VLOG_WARN_RL(&rl, "Couldn't find EVPN binding for
> "ETH_ADDR_FMT" "
> > +                         "MAC address.",
> ETH_ADDR_ARGS(static_fdb->mac));
> > +            continue;
> > +        }
> > +
> > +        fdb = evpn_fdb_find(f_ctx_out->fdbs, static_fdb->mac);
> > +        if (!fdb) {
> > +            fdb = evpn_fdb_add(f_ctx_out->fdbs, static_fdb->mac);
> > +        }
> > +
> > +        bool updated = false;
> > +        if (fdb->binding_key != binding->tunnel_key) {
> > +            fdb->binding_key = binding->tunnel_key;
> > +            updated = true;
> > +        }
> > +
> > +        if (fdb->dp_key != binding->dp_key) {
> > +            fdb->dp_key = binding->dp_key;
> > +            updated = true;
> > +        }
> > +
> > +        if (updated) {
> > +            hmapx_add(f_ctx_out->updated_fdbs, fdb);
> > +        }
> > +
> > +        hmapx_find_and_delete(&stale_fdbs, fdb);
> > +    }
> > +
> > +    struct hmapx_node *node;
> > +    HMAPX_FOR_EACH (node, &stale_fdbs) {
> > +        fdb = node->data;
> > +
> > +        uuidset_insert(f_ctx_out->removed_fdbs, &fdb->flow_uuid);
> > +        hmap_remove(f_ctx_out->fdbs, &fdb->hmap_node);
> > +        free(fdb);
> > +    }
> > +
> > +    hmapx_destroy(&stale_fdbs);
> > +}
> > +
> > +void
> > +evpn_fdbs_destroy(struct hmap *fdbs)
> > +{
> > +    struct evpn_fdb *fdb;
> > +    HMAP_FOR_EACH_POP (fdb, hmap_node, fdbs) {
> > +        free(fdb);
> > +    }
> > +    hmap_destroy(fdbs);
> > +}
> > +
> > +void
> > +evpn_fdb_list(struct unixctl_conn *conn, int argc OVS_UNUSED,
> > +              const char *argv[] OVS_UNUSED, void *data_)
> > +{
> > +    struct hmap *fdbs = data_;
> > +    struct ds ds = DS_EMPTY_INITIALIZER;
> > +
> > +    const struct evpn_fdb *fdb;
> > +    HMAP_FOR_EACH (fdb, hmap_node, fdbs) {
> > +        ds_put_format(&ds, "UUID: "UUID_FMT", MAC: "ETH_ADDR_FMT", "
> > +                      "binding_key: %#"PRIx32", dp_key: %"PRIu32"\n",
> > +                      UUID_ARGS(&fdb->flow_uuid),
> ETH_ADDR_ARGS(fdb->mac),
> > +                      fdb->binding_key, fdb->dp_key);
> > +    }
> > +
> > +    unixctl_command_reply(conn, ds_cstr_ro(&ds));
> > +    ds_destroy(&ds);
> > +}
> > +
> > +static struct evpn_fdb *
> > +evpn_fdb_add(struct hmap *evpn_fdbs, struct eth_addr mac)
> > +{
> > +    struct evpn_fdb *fdb = xmalloc(sizeof *fdb);
> > +    *fdb = (struct evpn_fdb) {
> > +        .flow_uuid = uuid_random(),
> > +        .mac = mac,
> > +        .binding_key = 0,
> > +        .dp_key = 0,
> > +    };
> > +
> > +    uint32_t hash = hash_bytes(&mac, sizeof mac, 0);
> > +    hmap_insert(evpn_fdbs, &fdb->hmap_node, hash);
> > +
> > +    return fdb;
> > +}
> > +
> > +static struct evpn_fdb *
> > +evpn_fdb_find(const struct hmap *evpn_fdbs, struct eth_addr mac)
> > +{
> > +    uint32_t hash = hash_bytes(&mac, sizeof mac, 0);
> > +
> > +    struct evpn_fdb *fdb;
> > +    HMAP_FOR_EACH_WITH_HASH (fdb, hmap_node, hash, evpn_fdbs) {
> > +        if (eth_addr_equals(fdb->mac, mac)) {
> > +            return fdb;
> > +        }
> > +    }
> > +
> > +    return NULL;
> > +}
> > diff --git a/controller/evpn-fdb.h b/controller/evpn-fdb.h
> > new file mode 100644
> > index 000000000..a38718cd9
> > --- /dev/null
> > +++ b/controller/evpn-fdb.h
> > @@ -0,0 +1,59 @@
> > +/* Copyright (c) 2025, Red Hat, Inc.
> > + *
> > + * Licensed under the Apache License, Version 2.0 (the "License");
> > + * you may not use this file except in compliance with the License.
> > + * You may obtain a copy of the License at:
> > + *
> > + *     http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing, software
> > + * distributed under the License is distributed on an "AS IS" BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> > + * See the License for the specific language governing permissions and
> > + * limitations under the License.
> > + */
> > +
> > +#ifndef EVPN_FDB_H
> > +#define EVPN_FDB_H 1
> > +
> > +#include <stdint.h>
> > +
> > +#include "hmapx.h"
> > +#include "openvswitch/hmap.h"
> > +#include "uuidset.h"
> > +
> > +struct unixctl_conn;
> > +
> > +struct evpn_fdb_ctx_in {
> > +    /* Contains 'struct evpn_binding'. */
> > +    const struct hmap *bindings;
> > +    /* Contains 'struct evpn_static_fdb'. */
> > +    const struct hmap *static_fdbs;
> > +};
> > +
> > +struct evpn_fdb_ctx_out {
> > +    /* Contains 'struct evpn_fdb'. */
> > +    struct hmap *fdbs;
> > +    /* Contains pointers to 'struct evpn_binding'. */
> > +    struct hmapx *updated_fdbs;
> > +    /* Contains 'flow_uuid' from removed 'struct evpn_binding'. */
> > +    struct uuidset *removed_fdbs;
> > +};
> > +
> > +struct evpn_fdb {
> > +    struct hmap_node hmap_node;
> > +    /* UUID used to identify physical flows related to this FDB. */
> > +    struct uuid flow_uuid;
> > +    /* IP address of the remote VTEP. */
> > +    struct eth_addr mac;
> > +    /* Local tunnel key to identify the binding. */
> > +    uint32_t binding_key;
> > +    uint32_t dp_key;
> > +};
> > +
> > +void evpn_fdb_run(const struct evpn_fdb_ctx_in *, struct
> evpn_fdb_ctx_out *);
> > +void evpn_fdbs_destroy(struct hmap *fdbs);
> > +void evpn_fdb_list(struct unixctl_conn *conn, int argc,
> > +                   const char *argv[], void *data_);
> > +
> > +#endif /* EVPN_FDB_H */
> > diff --git a/controller/lflow.h b/controller/lflow.h
> > index c2d277078..c8a87c886 100644
> > --- a/controller/lflow.h
> > +++ b/controller/lflow.h
> > @@ -102,6 +102,7 @@ struct uuid;
> >  #define OFTABLE_FLOOD_REMOTE_CHASSIS     84
> >  #define OFTABLE_CT_STATE_SAVE            85
> >  #define OFTABLE_CT_ORIG_PROTO_LOAD       86
> > +#define OFTABLE_GET_REMOTE_FDB           87
> >
> >  /* Common defines shared between some controller components. */
> >  #define CHASSIS_FLOOD_INDEX_START 0x8000
> > diff --git a/controller/neighbor-exchange-stub.c
> b/controller/neighbor-exchange-stub.c
> > index d314543be..272c14007 100644
> > --- a/controller/neighbor-exchange-stub.c
> > +++ b/controller/neighbor-exchange-stub.c
> > @@ -40,3 +40,8 @@ evpn_remote_vtep_list(struct unixctl_conn *conn
> OVS_UNUSED,
> >                        void *data_ OVS_UNUSED)
> >  {
> >  }
> > +
> > +void
> > +evpn_static_fdbs_clear(struct hmap *static_fdbs OVS_UNUSED)
> > +{
> > +}
> > diff --git a/controller/neighbor-exchange.c
> b/controller/neighbor-exchange.c
> > index 0fec5e59d..43b1477c6 100644
> > --- a/controller/neighbor-exchange.c
> > +++ b/controller/neighbor-exchange.c
> > @@ -31,6 +31,7 @@
> >  VLOG_DEFINE_THIS_MODULE(neighbor_exchange);
> >
> >  static bool neighbor_is_valid_remote_vtep(struct ne_nl_received_neigh
> *);
> > +static bool neighbor_is_valid_static_fdb(struct ne_nl_received_neigh *);
> >  static uint32_t evpn_remote_vtep_hash(const struct in6_addr *ip,
> >                                        uint16_t port, uint32_t vni);
> >  static void evpn_remote_vtep_add(struct hmap *remote_vteps, struct
> in6_addr ip,
> > @@ -38,7 +39,13 @@ static void evpn_remote_vtep_add(struct hmap
> *remote_vteps, struct in6_addr ip,
> >  static struct evpn_remote_vtep *evpn_remote_vtep_find(
> >      const struct hmap *remote_vteps, struct in6_addr *ip,
> >      uint16_t port, uint32_t vni);
> > -
> > +static void evpn_static_fdb_add(struct hmap *static_fdbs, struct
> eth_addr mac,
> > +                                struct in6_addr ip, uint32_t vni);
> > +static struct evpn_static_fdb *evpn_static_fdb_find(
> > +    const struct hmap *static_fdbs, struct eth_addr mac,
> > +    struct in6_addr ip, uint32_t vni);
> > +static uint32_t evpn_static_fdb_hash(const struct eth_addr *mac,
> > +                                     const struct in6_addr *ip,
> uint32_t vni);
> >
> >  /* Last neighbor_exchange netlink operation. */
> >  static int neighbor_exchange_nl_status;
> > @@ -94,6 +101,13 @@ neighbor_exchange_run(const struct
> neighbor_exchange_ctx_in *n_ctx_in,
> >                          evpn_remote_vtep_add(n_ctx_out->remote_vteps,
> ne->addr,
> >                                               port, nim->vni);
> >                      }
> > +                } else if (neighbor_is_valid_static_fdb(ne)) {
> > +                    if (!evpn_static_fdb_find(n_ctx_out->static_fdbs,
> > +                                              ne->lladdr, ne->addr,
> > +                                              nim->vni)) {
> > +                        evpn_static_fdb_add(n_ctx_out->static_fdbs,
> ne->lladdr,
> > +                                            ne->addr, nim->vni);
> > +                    }
> >                  }
> >              }
> >          }
> > @@ -117,6 +131,13 @@ neighbor_is_valid_remote_vtep(struct
> ne_nl_received_neigh *ne)
> >             ne->state & NUD_PERMANENT;
> >  }
> >
> > +static bool
> > +neighbor_is_valid_static_fdb(struct ne_nl_received_neigh *ne)
> > +{
> > +    return !eth_addr_is_zero(ne->lladdr) &&
> > +           ipv6_addr_is_set(&ne->addr) && ne->flags & NTF_EXT_LEARNED;
> > +}
> > +
> >  void
> >  evpn_remote_vteps_clear(struct hmap *remote_vteps)
> >  {
> > @@ -145,6 +166,15 @@ evpn_remote_vtep_list(struct unixctl_conn *conn,
> int argc OVS_UNUSED,
> >      ds_destroy(&ds);
> >  }
> >
> > +void
> > +evpn_static_fdbs_clear(struct hmap *static_fdbs)
> > +{
> > +    struct evpn_static_fdb *fdb;
> > +    HMAP_FOR_EACH_POP (fdb, hmap_node, static_fdbs) {
> > +        free(fdb);
> > +    }
> > +}
> > +
> >  static void
> >  evpn_remote_vtep_add(struct hmap *remote_vteps, struct in6_addr ip,
> >                       uint16_t port, uint32_t vni)
> > @@ -188,3 +218,48 @@ evpn_remote_vtep_hash(const struct in6_addr *ip,
> uint16_t port,
> >
> >      return hash;
> >  }
> > +
> > +static void
> > +evpn_static_fdb_add(struct hmap *static_fdbs, struct eth_addr mac,
> > +                    struct in6_addr ip, uint32_t vni)
> > +{
> > +    struct evpn_static_fdb *fdb = xmalloc(sizeof *fdb);
> > +    *fdb = (struct evpn_static_fdb) {
> > +        .mac = mac,
> > +        .ip = ip,
> > +        .vni = vni,
> > +    };
> > +
> > +    hmap_insert(static_fdbs, &fdb->hmap_node,
> > +                evpn_static_fdb_hash(&mac, &ip, vni));
> > +}
> > +
> > +static struct evpn_static_fdb *
> > +evpn_static_fdb_find(const struct hmap *static_fdbs, struct eth_addr
> mac,
> > +                     struct in6_addr ip, uint32_t vni)
> > +{
> > +    uint32_t hash = evpn_static_fdb_hash(&mac, &ip, vni);
> > +
> > +    struct evpn_static_fdb *fdb;
> > +    HMAP_FOR_EACH_WITH_HASH (fdb, hmap_node, hash, static_fdbs) {
> > +        if (eth_addr_equals(fdb->mac, mac) &&
> > +            ipv6_addr_equals(&fdb->ip, &ip) &&
> > +            fdb->vni == vni) {
> > +            return fdb;
> > +        }
> > +    }
> > +
> > +    return NULL;
> > +}
> > +
> > +static uint32_t
> > +evpn_static_fdb_hash(const struct eth_addr *mac, const struct in6_addr
> *ip,
> > +                     uint32_t vni)
> > +{
> > +    uint32_t hash = 0;
> > +    hash = hash_bytes(mac, sizeof *mac, hash);
> > +    hash = hash_add_in6_addr(hash, ip);
> > +    hash = hash_add(hash, vni);
> > +
> > +    return hash;
> > +}
> > diff --git a/controller/neighbor-exchange.h
> b/controller/neighbor-exchange.h
> > index dba97fdb9..208107909 100644
> > --- a/controller/neighbor-exchange.h
> > +++ b/controller/neighbor-exchange.h
> > @@ -34,6 +34,8 @@ struct neighbor_exchange_ctx_out {
> >      struct hmap neighbor_table_watches;
> >      /* Contains 'struct evpn_remote_vtep'. */
> >      struct hmap *remote_vteps;
> > +    /* Contains 'struct evpn_static_fdb'. */
> > +    struct hmap *static_fdbs;
> >  };
> >
> >  struct evpn_remote_vtep {
> > @@ -46,11 +48,22 @@ struct evpn_remote_vtep {
> >      uint32_t vni;
> >  };
> >
> > +struct evpn_static_fdb {
> > +    struct hmap_node hmap_node;
> > +    /* MAC address of the remote workload. */
> > +    struct eth_addr mac;
> > +    /* Destination ip of the remote tunnel. */
> > +    struct in6_addr ip;
> > +    /* VNI of the VTEP. */
> > +    uint32_t vni;
> > +};
> > +
> >  void neighbor_exchange_run(const struct neighbor_exchange_ctx_in *,
> >                             struct neighbor_exchange_ctx_out *);
> >  int neighbor_exchange_status_run(void);
> >  void evpn_remote_vteps_clear(struct hmap *remote_vteps);
> >  void evpn_remote_vtep_list(struct unixctl_conn *conn, int argc,
> >                             const char *argv[], void *data_);
> > +void evpn_static_fdbs_clear(struct hmap *static_fdbs);
> >
> >  #endif  /* NEIGHBOR_EXCHANGE_H */
> > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> > index 2f2959edb..a3d4f28c6 100644
> > --- a/controller/ovn-controller.c
> > +++ b/controller/ovn-controller.c
> > @@ -99,6 +99,7 @@
> >  #include "neighbor-exchange.h"
> >  #include "neighbor-table-notify.h"
> >  #include "evpn-binding.h"
> > +#include "evpn-fdb.h"
> >
> >  VLOG_DEFINE_THIS_MODULE(main);
> >
> > @@ -4576,6 +4577,15 @@ struct ed_type_evpn_vtep_binding {
> >      struct hmap tunnel_keys;
> >  };
> >
> > +struct ed_type_evpn_fdb {
> > +    /* Contains 'struct evpn_fdb'. */
> > +    struct hmap fdbs;
> > +    /* Contains pointers to 'struct evpn_fdb'. */
> > +    struct hmapx updated_fdbs;
> > +    /* Contains 'flow_uuid' from removed 'struct evpn_fdb'. */
> > +    struct uuidset removed_fdbs;
> > +};
> > +
> >  static void init_physical_ctx(struct engine_node *node,
> >                                struct ed_type_runtime_data *rt_data,
> >                                struct ed_type_non_vif_data *non_vif_data,
> > @@ -4633,6 +4643,9 @@ static void init_physical_ctx(struct engine_node
> *node,
> >      struct ed_type_evpn_vtep_binding *eb_data =
> >          engine_get_input_data("evpn_vtep_binding", node);
> >
> > +    struct ed_type_evpn_fdb *efdb_data =
> > +        engine_get_input_data("evpn_fdb", node);
> > +
> >      parse_encap_ips(ovs_table, &p_ctx->n_encap_ips, &p_ctx->encap_ips);
> >      p_ctx->sbrec_port_binding_by_name = sbrec_port_binding_by_name;
> >      p_ctx->sbrec_port_binding_by_datapath =
> sbrec_port_binding_by_datapath;
> > @@ -4652,6 +4665,7 @@ static void init_physical_ctx(struct engine_node
> *node,
> >      p_ctx->always_tunnel = n_opts->always_tunnel;
> >      p_ctx->evpn_bindings = &eb_data->bindings;
> >      p_ctx->evpn_multicast_groups = &eb_data->multicast_groups;
> > +    p_ctx->evpn_fdbs = &efdb_data->fdbs;
> >
> >      struct controller_engine_ctx *ctrl_ctx =
> engine_get_context()->client_ctx;
> >      p_ctx->if_mgr = ctrl_ctx->if_mgr;
> > @@ -4964,6 +4978,18 @@ pflow_output_evpn_binding_handler(struct
> engine_node *node, void *data)
> >      return EN_HANDLED_UPDATED;
> >  }
> >
> > +static enum engine_input_handler_result
> > +pflow_output_fdb_handler(struct engine_node *node, void *data)
> > +{
> > +    struct ed_type_pflow_output *pfo = data;
> > +    struct ed_type_evpn_fdb *ef_data =
> > +        engine_get_input_data("evpn_fdb", node);
> > +
> > +    physical_handle_evpn_fdb_changes(&pfo->flow_table,
> &ef_data->updated_fdbs,
> > +                                     &ef_data->removed_fdbs);
> > +    return EN_HANDLED_UPDATED;
> > +}
> > +
> >  static void *
> >  en_controller_output_init(struct engine_node *node OVS_UNUSED,
> >                            struct engine_arg *arg OVS_UNUSED)
> > @@ -5897,6 +5923,8 @@ en_neighbor_table_notify_run(struct engine_node
> *node OVS_UNUSED,
> >  struct ed_type_neighbor_exchange {
> >      /* Contains 'struct evpn_remote_vtep'. */
> >      struct hmap remote_vteps;
> > +    /* Contains 'struct evpn_static_fdb'. */
> > +    struct hmap static_fdbs;
> >  };
> >
> >  static void *
> > @@ -5906,6 +5934,7 @@ en_neighbor_exchange_init(struct engine_node *node
> OVS_UNUSED,
> >      struct ed_type_neighbor_exchange *data = xmalloc(sizeof *data);
> >      *data = (struct ed_type_neighbor_exchange) {
> >          .remote_vteps = HMAP_INITIALIZER(&data->remote_vteps),
> > +        .static_fdbs = HMAP_INITIALIZER(&data->static_fdbs),
> >      };
> >
> >      return data;
> > @@ -5916,7 +5945,9 @@ en_neighbor_exchange_cleanup(void *data_)
> >  {
> >      struct ed_type_neighbor_exchange *data = data_;
> >      evpn_remote_vteps_clear(&data->remote_vteps);
> > +    evpn_static_fdbs_clear(&data->static_fdbs);
> >      hmap_destroy(&data->remote_vteps);
> > +    hmap_destroy(&data->static_fdbs);
> >  }
> >
> >  static enum engine_node_state
> > @@ -5927,6 +5958,7 @@ en_neighbor_exchange_run(struct engine_node *node,
> void *data_)
> >          engine_get_input_data("neighbor", node);
> >
> >      evpn_remote_vteps_clear(&data->remote_vteps);
> > +    evpn_static_fdbs_clear(&data->static_fdbs);
> >
> >      struct neighbor_exchange_ctx_in n_ctx_in = {
> >          .monitored_interfaces = &neighbor_data->monitored_interfaces,
> > @@ -5935,6 +5967,7 @@ en_neighbor_exchange_run(struct engine_node *node,
> void *data_)
> >          .neighbor_table_watches =
> >              HMAP_INITIALIZER(&n_ctx_out.neighbor_table_watches),
> >          .remote_vteps = &data->remote_vteps,
> > +        .static_fdbs = &data->static_fdbs,
> >      };
> >
> >      neighbor_exchange_run(&n_ctx_in, &n_ctx_out);
> > @@ -6094,7 +6127,7 @@ evpn_vtep_binding_datapath_binding_handler(struct
> engine_node *node,
> >  {
> >      const struct sbrec_datapath_binding_table *dp_table =
> >          EN_OVSDB_GET(engine_get_input("SB_datapath_binding", node));
> > -    struct ed_type_runtime_data *rt_data =
> > +    const struct ed_type_runtime_data *rt_data =
> >          engine_get_input_data("runtime_data", node);
> >
> >      const struct sbrec_datapath_binding *dp;
> > @@ -6126,6 +6159,81 @@ evpn_vtep_binding_datapath_binding_handler(struct
> engine_node *node,
> >      return EN_HANDLED_UNCHANGED;
> >  }
> >
> > +static void *
> > +en_evpn_fdb_init(struct engine_node *node OVS_UNUSED,
> > +                 struct engine_arg *arg OVS_UNUSED)
> > +{
> > +    struct ed_type_evpn_fdb *data = xmalloc(sizeof *data);
> > +    *data = (struct ed_type_evpn_fdb) {
> > +        .fdbs = HMAP_INITIALIZER(&data->fdbs),
> > +        .updated_fdbs = HMAPX_INITIALIZER(&data->updated_fdbs),
> > +        .removed_fdbs = UUIDSET_INITIALIZER(&data->removed_fdbs),
> > +    };
> > +
> > +    return data;
> > +}
> > +
> > +static void
> > +en_evpn_fdb_clear_tracked_data(void *data_)
> > +{
> > +    struct ed_type_evpn_fdb *data = data_;
> > +    hmapx_clear(&data->updated_fdbs);
> > +    uuidset_clear(&data->removed_fdbs);
> > +}
> > +
> > +static void
> > +en_evpn_fdb_cleanup(void *data_)
> > +{
> > +    struct ed_type_evpn_fdb *data = data_;
> > +    evpn_fdbs_destroy(&data->fdbs);
> > +    hmapx_destroy(&data->updated_fdbs);
> > +    uuidset_destroy(&data->removed_fdbs);
> > +}
> > +
> > +static enum engine_node_state
> > +en_evpn_fdb_run(struct engine_node *node, void *data_)
> > +{
> > +    struct ed_type_evpn_fdb *data = data_;
> > +    const struct ed_type_neighbor_exchange *ne_data =
> > +        engine_get_input_data("neighbor_exchange", node);
> > +    const struct ed_type_evpn_vtep_binding *eb_data =
> > +        engine_get_input_data("evpn_vtep_binding", node);
> > +
> > +    struct evpn_fdb_ctx_in f_ctx_in = {
> > +        .static_fdbs = &ne_data->static_fdbs,
> > +        .bindings = &eb_data->bindings,
> > +    };
> > +
> > +    struct evpn_fdb_ctx_out f_ctx_out = {
> > +        .fdbs = &data->fdbs,
> > +        .updated_fdbs = &data->updated_fdbs,
> > +        .removed_fdbs = &data->removed_fdbs,
> > +    };
> > +
> > +    evpn_fdb_run(&f_ctx_in, &f_ctx_out);
> > +
> > +    if (hmapx_count(&data->updated_fdbs) ||
> > +        uuidset_count(&data->removed_fdbs)) {
> > +        return EN_UPDATED;
> > +    }
> > +
> > +    return EN_UNCHANGED;
> > +}
> > +
> > +static enum engine_input_handler_result
> > +evpn_fdb_vtep_binding_handler(struct engine_node *node, void *data
> OVS_UNUSED)
> > +{
> > +    const struct ed_type_evpn_vtep_binding *eb_data =
> > +        engine_get_input_data("evpn_vtep_binding", node);
> > +
> > +    if (hmapx_is_empty(&eb_data->updated_bindings) &&
> > +        uuidset_is_empty(&eb_data->removed_bindings)) {
> > +        return EN_HANDLED_UNCHANGED;
> > +    }
> > +
> > +    return EN_UNHANDLED;
> > +}
> > +
> >  /* Returns false if the northd internal version stored in SB_Global
> >   * and ovn-controller internal version don't match.
> >   */
> > @@ -6441,6 +6549,7 @@ main(int argc, char *argv[])
> >      ENGINE_NODE(neighbor_exchange);
> >      ENGINE_NODE(neighbor_exchange_status);
> >      ENGINE_NODE(evpn_vtep_binding, CLEAR_TRACKED_DATA);
> > +    ENGINE_NODE(evpn_fdb, CLEAR_TRACKED_DATA);
> >
> >  #define SB_NODE(NAME) ENGINE_NODE_SB(NAME);
> >      SB_NODES
> > @@ -6688,8 +6797,14 @@ main(int argc, char *argv[])
> >      engine_add_input(&en_evpn_vtep_binding, &en_sb_datapath_binding,
> >                       evpn_vtep_binding_datapath_binding_handler);
> >
> > +    engine_add_input(&en_evpn_fdb, &en_neighbor_exchange, NULL);
> > +    engine_add_input(&en_evpn_fdb, &en_evpn_vtep_binding,
> > +                     evpn_fdb_vtep_binding_handler);
> > +
> >      engine_add_input(&en_pflow_output, &en_evpn_vtep_binding,
> >                       pflow_output_evpn_binding_handler);
> > +    engine_add_input(&en_pflow_output, &en_evpn_fdb,
> > +                     pflow_output_fdb_handler);
> >
> >      engine_add_input(&en_controller_output, &en_dns_cache,
> >                       NULL);
> > @@ -6771,6 +6886,8 @@ main(int argc, char *argv[])
> >          engine_get_internal_data(&en_neighbor_exchange);
> >      struct ed_type_evpn_vtep_binding *eb_data =
> >          engine_get_internal_data(&en_evpn_vtep_binding);
> > +    struct ed_type_evpn_fdb *efdb_data =
> > +        engine_get_internal_data(&en_evpn_fdb);
> >
> >      ofctrl_init(&lflow_output_data->group_table,
> >                  &lflow_output_data->meter_table);
> > @@ -6796,6 +6913,9 @@ main(int argc, char *argv[])
> >      unixctl_command_register("evpn/vtep-multicast-group-list", "", 0, 0,
> >                               evpn_multicast_group_list,
> >                               &eb_data->multicast_groups);
> > +    unixctl_command_register("evpn/vtep-fdb-list", "", 0, 0,
> > +                             evpn_fdb_list,
> > +                             &efdb_data->fdbs);
> >
> >      struct pending_pkt pending_pkt = { .conn = NULL };
> >      unixctl_command_register("inject-pkt", "MICROFLOW", 1, 1,
> inject_pkt,
> > diff --git a/controller/physical.c b/controller/physical.c
> > index 0a4b31040..be233cba0 100644
> > --- a/controller/physical.c
> > +++ b/controller/physical.c
> > @@ -20,6 +20,7 @@
> >  #include "ct-zone.h"
> >  #include "encaps.h"
> >  #include "evpn-binding.h"
> > +#include "evpn-fdb.h"
> >  #include "flow.h"
> >  #include "ha-chassis.h"
> >  #include "lflow.h"
> > @@ -2777,6 +2778,23 @@ physical_consider_evpn_multicast(const struct
> evpn_multicast_group *mc_group,
> >      }
> >  }
> >
> > +static void
> > +physical_consider_evpn_fdb(const struct evpn_fdb *fdb,
> > +                           struct ofpbuf *ofpacts, struct match *match,
> > +                           struct ovn_desired_flow_table *flow_table)
> > +{
> > +    ofpbuf_clear(ofpacts);
> > +    match_init_catchall(match);
> > +
> > +    match_set_metadata(match, htonll(fdb->dp_key));
> > +    match_set_dl_dst(match, fdb->mac);
> > +
> > +    put_load(fdb->binding_key, MFF_LOG_REMOTE_OUTPORT, 0, 32, ofpacts);
> > +    ofctrl_add_flow(flow_table, OFTABLE_GET_REMOTE_FDB, 150,
> > +                    fdb->flow_uuid.parts[0],
> > +                    match, ofpacts, &fdb->flow_uuid);
>
> Nit: a comment (or a note about this in ovn-architecture if we go that
> way in the previous patches) about what this flow does might be useful.
>
> > +}
> > +
> >  static void
> >  physical_eval_evpn_flows(const struct physical_ctx *ctx,
> >                           struct ofpbuf *ofpacts,
> > @@ -2803,6 +2821,11 @@ physical_eval_evpn_flows(const struct
> physical_ctx *ctx,
> >          physical_consider_evpn_multicast(mc_group, &local_ip, ofpacts,
> >                                           &match, flow_table, ipv4);
> >      }
> > +
> > +    const struct evpn_fdb *fdb;
> > +    HMAP_FOR_EACH (fdb, hmap_node, ctx->evpn_fdbs) {
> > +        physical_consider_evpn_fdb(fdb, ofpacts, &match, flow_table);
> > +    }
> >  }
> >
> >  static void
> > @@ -2961,6 +2984,31 @@ physical_handle_evpn_binding_changes(
> >      }
> >  }
> >
> > +void
> > +physical_handle_evpn_fdb_changes(struct ovn_desired_flow_table
> *flow_table,
> > +                                 const struct hmapx *updated_fdbs,
> > +                                 const struct uuidset *removed_fdbs)
> > +{
> > +    struct ofpbuf ofpacts;
> > +    ofpbuf_init(&ofpacts, 0);
> > +    struct match match = MATCH_CATCHALL_INITIALIZER;
> > +
> > +    const struct hmapx_node *node;
> > +    HMAPX_FOR_EACH (node, updated_fdbs) {
> > +        const struct evpn_fdb *fdb = node->data;
> > +
> > +        ofctrl_remove_flows(flow_table, &fdb->flow_uuid);
> > +        physical_consider_evpn_fdb(fdb, &ofpacts, &match, flow_table);
> > +    }
> > +
> > +    ofpbuf_uninit(&ofpacts);
> > +
> > +    const struct uuidset_node *uuidset_node;
> > +    UUIDSET_FOR_EACH (uuidset_node, removed_fdbs) {
> > +        ofctrl_remove_flows(flow_table, &uuidset_node->uuid);
> > +    }
> > +}
> > +
> >  void
> >  physical_run(struct physical_ctx *p_ctx,
> >               struct ovn_desired_flow_table *flow_table)
> > diff --git a/controller/physical.h b/controller/physical.h
> > index e0443924b..37be46380 100644
> > --- a/controller/physical.h
> > +++ b/controller/physical.h
> > @@ -71,6 +71,7 @@ struct physical_ctx {
> >      bool always_tunnel;
> >      const struct hmap *evpn_bindings;
> >      const struct hmap *evpn_multicast_groups;
> > +    const struct hmap *evpn_fdbs;
> >
> >      /* Set of port binding names that have been already reprocessed
> during
> >       * the I-P run. */
> > @@ -95,4 +96,7 @@ void physical_handle_evpn_binding_changes(
> >      const struct hmapx *updated_multicast_groups,
> >      const struct uuidset *removed_bindings,
> >      const struct uuidset *removed_multicast_groups);
> > +void physical_handle_evpn_fdb_changes(struct ovn_desired_flow_table *,
> > +                                      const struct hmapx *updated_fdbs,
> > +                                      const struct uuidset
> *removed_fdbs);
> >  #endif /* controller/physical.h */
> > diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at
> > index d6529e015..25b3fb68d 100644
> > --- a/tests/ovn-macros.at
> > +++ b/tests/ovn-macros.at
> > @@ -1502,5 +1502,6 @@ m4_define([OFTABLE_CT_ORIG_TP_DST_LOAD], [83])
> >  m4_define([OFTABLE_FLOOD_REMOTE_CHASSIS], [84])
> >  m4_define([OFTABLE_CT_STATE_SAVE], [85])
> >  m4_define([OFTABLE_CT_ORIG_PROTO_LOAD], [86])
> > +m4_define([OFTABLE_GET_REMOTE_FDB], [87])
> >
> >  m4_define([OFTABLE_SAVE_INPORT_HEX], [m4_eval(OFTABLE_SAVE_INPORT, 16)])
>
> Regards,
> Dumitru
>
>
Hi Dumitru,

thank you for the review. I'll keep that in mind
for the BGP document.

Thanks,
Ales
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to