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