On Wed, Aug 6, 2025 at 12:53 PM Dumitru Ceara <dce...@redhat.com> wrote:
> Hi Ales, > > Overall this patch looks good to me. I only have a few minor comments > below. > Hi Dumitru, thank you for the review. > > On 7/25/25 8:03 AM, Ales Musil wrote: > > In order to get the VTEP setup listeners for each special interface > > that is dedicated to given vni. Those interfaces need to be > > Nit: s/to given vni/to a given VNI/ > > > part of the VRF, created by CMS. Once those listeners are in place > > ovn-controller will receive notifications about remote VTEPs. > > > > I think, maybe as follow up or in later revisions (if we get a chance > to), we should add a small document (tutorial?) describing how the > integration bits should be set up. > Let's try it for v3, possibly a follow up patch to not delay v2. > > > Create remote VTEP representation based on the data received from > > netlink neighbor table. There are three key attributes that > > uniquely identify each remote VTEP: > > 1) IP of the remote tunnel. > > 2) Destination port of the remote tunnel. > > 3) VNI. > > > > Crate map of all remote VTEPs based on those three attributes. > > Typo: "Crate". I'd say "Create a map of..". > > > The map will be used later on to crate the EVPN binding. One > > thing to note is that all of this is specific to each ovn-controller. > > This is one of the reasons why those data are local to each > > ovn-controller, the second reason is scalability as we would have > > possibly duplicate SB entries differentiated only by residing > > chassis. > > > > Note that there isn't any way to set vni for given LS that will > > be part of future patch. > > > > Maybe explicitly mention the option name here? ("dynamic-routing-vni") > > > Signed-off-by: Ales Musil <amu...@redhat.com> > > --- > > controller/neighbor-exchange-stub.c | 12 +++ > > controller/neighbor-exchange.c | 116 ++++++++++++++++++++++++++-- > > controller/neighbor-exchange.h | 22 +++++- > > controller/neighbor.c | 98 +++++++++++++++++++---- > > controller/neighbor.h | 11 +++ > > controller/ovn-controller.c | 108 +++++++++++++++++++++++--- > > lib/ovn-util.c | 6 ++ > > lib/ovn-util.h | 2 + > > 8 files changed, 346 insertions(+), 29 deletions(-) > > > > diff --git a/controller/neighbor-exchange-stub.c > b/controller/neighbor-exchange-stub.c > > index a42df84c2..d314543be 100644 > > --- a/controller/neighbor-exchange-stub.c > > +++ b/controller/neighbor-exchange-stub.c > > @@ -28,3 +28,15 @@ neighbor_exchange_status_run(void) > > { > > return 0; > > } > > + > > +void > > +evpn_remote_vteps_clear(struct hmap *remote_vteps OVS_UNUSED) > > +{ > > +} > > + > > +void > > +evpn_remote_vtep_list(struct unixctl_conn *conn OVS_UNUSED, > > + int argc OVS_UNUSED, const char *argv[] > OVS_UNUSED, > > + void *data_ OVS_UNUSED) > > +{ > > +} > > diff --git a/controller/neighbor-exchange.c > b/controller/neighbor-exchange.c > > index 4750d4f88..0fec5e59d 100644 > > --- a/controller/neighbor-exchange.c > > +++ b/controller/neighbor-exchange.c > > @@ -15,12 +15,30 @@ > > > > #include <config.h> > > > > +#include <linux/neighbour.h> > > + > > #include "host-if-monitor.h" > > #include "neighbor.h" > > #include "neighbor-exchange.h" > > #include "neighbor-exchange-netlink.h" > > #include "neighbor-table-notify.h" > > +#include "openvswitch/vlog.h" > > +#include "ovn-util.h" > > +#include "packets.h" > > #include "vec.h" > > +#include "unixctl.h" > > + > > +VLOG_DEFINE_THIS_MODULE(neighbor_exchange); > > + > > +static bool neighbor_is_valid_remote_vtep(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, > > + uint16_t port, uint32_t vni); > > +static struct evpn_remote_vtep *evpn_remote_vtep_find( > > + const struct hmap *remote_vteps, struct in6_addr *ip, > > + uint16_t port, uint32_t vni); > > + > > > > /* Last neighbor_exchange netlink operation. */ > > static int neighbor_exchange_nl_status; > > @@ -66,12 +84,19 @@ neighbor_exchange_run(const struct > neighbor_exchange_ctx_in *n_ctx_in, > > &received_neighbors) > > ); > > > > - /* XXX: TODO GLUE: sync received neighbors to: > > - * - SB: for remote vtep entries > > - * https://issues.redhat.com/browse/FDP-1385 > > - * - in memory table for remote neighbor entries > > - * https://issues.redhat.com/browse/FDP-1387 > > - */ > > + if (nim->type == NEIGH_IFACE_VXLAN) { > > + struct ne_nl_received_neigh *ne; > > + VECTOR_FOR_EACH_PTR (&received_neighbors, ne) { > > + if (neighbor_is_valid_remote_vtep(ne)) { > > + uint16_t port = ne->port ? ne->port : > DEFAULT_VXLAN_PORT; > > + if (!evpn_remote_vtep_find(n_ctx_out->remote_vteps, > > + &ne->addr, port, > nim->vni)) { > > + evpn_remote_vtep_add(n_ctx_out->remote_vteps, > ne->addr, > > + port, nim->vni); > > + } > > + } > > + } > > + } > > > > > neighbor_table_add_watch_request(&n_ctx_out->neighbor_table_watches, > > if_index, nim->if_name); > > @@ -84,3 +109,82 @@ neighbor_exchange_status_run(void) > > { > > return neighbor_exchange_nl_status; > > } > > + > > +static bool > > +neighbor_is_valid_remote_vtep(struct ne_nl_received_neigh *ne) > > Nit: I think this should be part of neighbor-exchange-netlink.[ch]. > We're checking netlink/linux specific flags, it feels like it fits > better there. Also we already have ne_is_ovn_owned() there so we have a > precedent. > > > +{ > > + return eth_addr_is_zero(ne->lladdr) && ne->state & NUD_NOARP && > > + ne->state & NUD_PERMANENT; > > Nit: the mix of && and & makes me a bit uneasy, can you please add some > extra parenthesis? > > Also, a comment explaining that remote vtep neighbor entries are > > > +} > > + > > +void > > +evpn_remote_vteps_clear(struct hmap *remote_vteps) > > +{ > > + struct evpn_remote_vtep *vtep; > > + HMAP_FOR_EACH_POP (vtep, hmap_node, remote_vteps) { > > + free(vtep); > > + } > > +} > > + > > +void > > +evpn_remote_vtep_list(struct unixctl_conn *conn, int argc OVS_UNUSED, > > Super nit: the 'conn' argument name can be skipped. > > > + const char *argv[] OVS_UNUSED, void *data_) > > +{ > > + struct hmap *remote_vteps = data_; > > + struct ds ds = DS_EMPTY_INITIALIZER; > > + > > + struct evpn_remote_vtep *vtep; > > + HMAP_FOR_EACH (vtep, hmap_node, remote_vteps) { > > + ds_put_cstr(&ds, "IP: "); > > + ipv6_format_mapped(&vtep->ip, &ds); > > + ds_put_format(&ds, ", port: %"PRIu16", vni: %"PRIu32"\n", > > + vtep->port, vtep->vni); > > + } > > + > > + unixctl_command_reply(conn, ds_cstr_ro(&ds)); > > + ds_destroy(&ds); > > +} > > + > > +static void > > +evpn_remote_vtep_add(struct hmap *remote_vteps, struct in6_addr ip, > > + uint16_t port, uint32_t vni) > > +{ > > + struct evpn_remote_vtep *vtep = xmalloc(sizeof *vtep); > > + *vtep = (struct evpn_remote_vtep) { > > + .ip = ip, > > + .port = port, > > + .vni = vni, > > + }; > > + > > + hmap_insert(remote_vteps, &vtep->hmap_node, > > + evpn_remote_vtep_hash(&ip, port, vni)); > > +} > > + > > +static struct evpn_remote_vtep * > > +evpn_remote_vtep_find(const struct hmap *remote_vteps, struct in6_addr > *ip, > > Nit: const struct in6_addr *ip > > > + uint16_t port, uint32_t vni) > > +{ > > + uint32_t hash = evpn_remote_vtep_hash(ip, port, vni); > > + > > + struct evpn_remote_vtep *vtep; > > + HMAP_FOR_EACH_WITH_HASH (vtep, hmap_node, hash, remote_vteps) { > > + if (ipv6_addr_equals(&vtep->ip, ip) && > > + vtep->port == port && vtep->vni == vni) { > > + return vtep; > > + } > > + } > > + > > + return NULL; > > +} > > + > > +static uint32_t > > +evpn_remote_vtep_hash(const struct in6_addr *ip, uint16_t port, > > + uint32_t vni) > > +{ > > + uint32_t hash = 0; > > + hash = hash_add_in6_addr(hash, ip); > > + hash = hash_add(hash, port); > > + hash = hash_add(hash, vni); > > + > > + return hash; > > +} > > diff --git a/controller/neighbor-exchange.h > b/controller/neighbor-exchange.h > > index afbbe9811..dba97fdb9 100644 > > --- a/controller/neighbor-exchange.h > > +++ b/controller/neighbor-exchange.h > > @@ -16,9 +16,14 @@ > > #ifndef NEIGHBOR_EXCHANGE_H > > #define NEIGHBOR_EXCHANGE_H 1 > > > > -#include "lib/sset.h" > > +#include <netinet/in.h> > > + > > #include "openvswitch/hmap.h" > > > > +#define DEFAULT_VXLAN_PORT 4789 > > + > > +struct unixctl_conn; > > + > > struct neighbor_exchange_ctx_in { > > /* Contains struct neighbor_interface_monitor pointers. */ > > const struct vector *monitored_interfaces; > > @@ -27,10 +32,25 @@ struct neighbor_exchange_ctx_in { > > struct neighbor_exchange_ctx_out { > > /* Contains struct neighbor_table_watch_request. */ > > struct hmap neighbor_table_watches; > > + /* Contains 'struct evpn_remote_vtep'. */ > > + struct hmap *remote_vteps; > > +}; > > + > > +struct evpn_remote_vtep { > > + struct hmap_node hmap_node; > > + /* IP address of the remote tunnel. */ > > + struct in6_addr ip; > > + /* Destination port of the remote tunnel. */ > > + uint16_t port; > > + /* 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_); > > > > #endif /* NEIGHBOR_EXCHANGE_H */ > > diff --git a/controller/neighbor.c b/controller/neighbor.c > > index 53e8999ed..ee77d02d6 100644 > > --- a/controller/neighbor.c > > +++ b/controller/neighbor.c > > @@ -18,11 +18,26 @@ > > #include "lib/hash.h" > > #include "lib/packets.h" > > #include "lib/sset.h" > > +#include "local_data.h" > > +#include "ovn-sb-idl.h" > > > > #include "neighbor.h" > > > > +static const char *neighbor_interface_prefixes[] = { > > + [NEIGH_IFACE_BRIDGE] = "br-", > > + [NEIGH_IFACE_VXLAN] = "vxlan-", > > + [NEIGH_IFACE_LOOPBACK] = "lo-", > > +}; > > + > > static void neighbor_interface_monitor_destroy( > > struct neighbor_interface_monitor *); > > +static bool neighbor_interface_with_vni_exists( > > + struct vector *monitored_interfaces, > > + uint32_t vni); > > +static struct neighbor_interface_monitor * > > +neighbor_interface_monitor_alloc(enum neighbor_family family, > > + enum neighbor_interface_type type, > > + uint32_t vni); > > > > uint32_t > > advertise_neigh_hash(const struct eth_addr *eth, const struct in6_addr > *ip) > > @@ -31,20 +46,46 @@ advertise_neigh_hash(const struct eth_addr *eth, > const struct in6_addr *ip) > > } > > > > void > > -neighbor_run(struct neighbor_ctx_in *n_ctx_in OVS_UNUSED, > > - struct neighbor_ctx_out *n_ctx_out OVS_UNUSED) > > +neighbor_run(struct neighbor_ctx_in *n_ctx_in, > > + struct neighbor_ctx_out *n_ctx_out) > > { > > - /* XXX: Not implemented yet. */ > > - > > - /* XXX: TODO GLUE: get information from (n_ctx_in) SB > (runtime-data) about: > > - * - local datapath vni (and listen on br-$vni, lo-$vni and > vxlan-$vni) > > - * for which we want to enable neighbor monitoring > > - * https://issues.redhat.com/browse/FDP-1385 > > - * - what FDB/neighbor entries to advertise > > - * https://issues.redhat.com/browse/FDP-1389 > > - * > > - * And populate that in n_ctx_out. > > - */ > > + struct local_datapath *ld; > > + HMAP_FOR_EACH (ld, hmap_node, n_ctx_in->local_datapaths) { > > + if (!ld->is_switch) { > > + continue; > > + } > > + > > + int64_t vni = ovn_smap_get_llong(&ld->datapath->external_ids, > > + "dynamic-routing-vni", -1); > > + if (!ovn_is_valid_vni(vni)) { > > + continue; > > + } > > + > > + if > (neighbor_interface_with_vni_exists(n_ctx_out->monitored_interfaces, > > + vni)) { > > + continue; > > + } > > + > > + struct neighbor_interface_monitor *vxlan = > > + neighbor_interface_monitor_alloc(NEIGH_AF_BRIDGE, > > + NEIGH_IFACE_VXLAN, vni); > > + vector_push(n_ctx_out->monitored_interfaces, &vxlan); > > + > > + struct neighbor_interface_monitor *lo = > > + neighbor_interface_monitor_alloc(NEIGH_AF_BRIDGE, > > + NEIGH_IFACE_LOOPBACK, vni); > > + vector_push(n_ctx_out->monitored_interfaces, &lo); > > + > > + struct neighbor_interface_monitor *br_v4 = > > + neighbor_interface_monitor_alloc(NEIGH_AF_INET, > > + NEIGH_IFACE_BRIDGE, vni); > > + vector_push(n_ctx_out->monitored_interfaces, &br_v4); > > + > > + struct neighbor_interface_monitor *br_v6 = > > + neighbor_interface_monitor_alloc(NEIGH_AF_INET6, > > + NEIGH_IFACE_BRIDGE, vni); > > + vector_push(n_ctx_out->monitored_interfaces, &br_v6); > > + } > > } > > > > void > > @@ -67,3 +108,34 @@ neighbor_interface_monitor_destroy(struct > neighbor_interface_monitor *nim) > > } > > free(nim); > > } > > + > > +static bool > > +neighbor_interface_with_vni_exists(struct vector *monitored_interfaces, > > + uint32_t vni) > > +{ > > + const struct neighbor_interface_monitor *nim; > > + VECTOR_FOR_EACH (monitored_interfaces, nim) { > > + if (nim->vni == vni) { > > + return true; > > + } > > + } > > + > > + return false; > > +} > > + > > +static struct neighbor_interface_monitor * > > +neighbor_interface_monitor_alloc(enum neighbor_family family, > > + enum neighbor_interface_type type, > > + uint32_t vni) > > +{ > > + struct neighbor_interface_monitor *nim = xmalloc(sizeof *nim); > > + *nim = (struct neighbor_interface_monitor) { > > + .family = family, > > + .announced_neighbors = > HMAP_INITIALIZER(&nim->announced_neighbors), > > + .type = type, > > + .vni = vni, > > + }; > > + snprintf(nim->if_name, sizeof nim->if_name, "%s%"PRIu32, > > + neighbor_interface_prefixes[type], vni); > > + return nim; > > +} > > diff --git a/controller/neighbor.h b/controller/neighbor.h > > index 3abc6e923..3dc21938b 100644 > > --- a/controller/neighbor.h > > +++ b/controller/neighbor.h > > @@ -40,6 +40,8 @@ enum neighbor_family { > > }; > > > > struct neighbor_ctx_in { > > + /* Contains 'struct local_datapath'. */ > > + const struct hmap *local_datapaths; > > }; > > > > struct neighbor_ctx_out { > > @@ -47,9 +49,18 @@ struct neighbor_ctx_out { > > struct vector *monitored_interfaces; > > }; > > > > +enum neighbor_interface_type { > > + NEIGH_IFACE_BRIDGE, > > + NEIGH_IFACE_VXLAN, > > + NEIGH_IFACE_LOOPBACK, > > +}; > > + > > + > > Nit: one newline too many. > > > struct neighbor_interface_monitor { > > enum neighbor_family family; > > char if_name[IFNAMSIZ + 1]; > > + enum neighbor_interface_type type; > > + uint32_t vni; > > > > /* Contains struct advertise_neighbor_entry - the entries that OVN > > * advertises on this interface. */ > > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > > index 1842d0184..90ef6011a 100644 > > --- a/controller/ovn-controller.c > > +++ b/controller/ovn-controller.c > > @@ -5737,7 +5737,10 @@ static enum engine_node_state > > en_neighbor_run(struct engine_node *node OVS_UNUSED, void *data) > > { > > struct ed_type_neighbor *ne_data = data; > > + struct ed_type_runtime_data *rt_data = > > + engine_get_input_data("runtime_data", node); > > struct neighbor_ctx_in n_ctx_in = { > > + .local_datapaths = &rt_data->local_datapaths, > > }; > > > > struct neighbor_ctx_out n_ctx_out = { > > @@ -5747,13 +5750,73 @@ en_neighbor_run(struct engine_node *node > OVS_UNUSED, void *data) > > neighbor_cleanup(&ne_data->monitored_interfaces); > > neighbor_run(&n_ctx_in, &n_ctx_out); > > > > - /* XXX: This should return EN_UPDATED once we actually process real > SB > > - * changes, i.e.: > > - * > > - * return EN_UPDATED; > > - */ > > + return EN_UPDATED; > > +} > > > > - return EN_UNCHANGED; > > +static enum engine_input_handler_result > > +neighbor_runtime_data_handler(struct engine_node *node, void *data > OVS_UNUSED) > > +{ > > + struct ed_type_runtime_data *rt_data = > > + engine_get_input_data("runtime_data", node); > > + > > + /* There are no tracked data. Fall back to full recompute. */ > > + if (!rt_data->tracked) { > > + return EN_UNHANDLED; > > + } > > + > > + struct tracked_datapath *tdp; > > + HMAP_FOR_EACH (tdp, node, &rt_data->tracked_dp_bindings) { > > + struct local_datapath *ld = > > + get_local_datapath(&rt_data->local_datapaths, > tdp->dp->tunnel_key); > > + if (!ld) { > > + continue; > > + } > > + > > + int64_t vni = ovn_smap_get_llong(&tdp->dp->external_ids, > > + "dynamic-routing-vni", -1); > > + if (!ovn_is_valid_vni(vni)) { > > + continue; > > + } > > + > > + if (tdp->tracked_type == TRACKED_RESOURCE_NEW || > > + tdp->tracked_type == TRACKED_RESOURCE_REMOVED) { > > + return EN_UNHANDLED; > > + } > > + } > > + > > + return EN_HANDLED_UNCHANGED; > > +} > > + > > +static enum engine_input_handler_result > > +neighbor_sb_datapath_binding_handler(struct engine_node *node, > > + void *data OVS_UNUSED) > > +{ > > + 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 = > > + engine_get_input_data("runtime_data", node); > > + > > + const struct sbrec_datapath_binding *dp; > > + SBREC_DATAPATH_BINDING_TABLE_FOR_EACH_TRACKED (dp, dp_table) { > > + if (sbrec_datapath_binding_is_new(dp) || > > + sbrec_datapath_binding_is_deleted(dp)) { > > + /* The removal and addition is handled via runtime_data. */ > > + return EN_HANDLED_UNCHANGED; > > + } > > + > > + struct local_datapath *ld = > > + get_local_datapath(&rt_data->local_datapaths, > dp->tunnel_key); > > + if (!ld || !ld->is_switch) { > > + continue; > > + } > > + > > + if (sbrec_datapath_binding_is_updated( > > + dp, SBREC_DATAPATH_BINDING_COL_EXTERNAL_IDS)) { > > + return EN_UNHANDLED; > > + } > > + } > > + > > + return EN_HANDLED_UNCHANGED; > > } > > > > struct ed_type_neighbor_table_notify { > > @@ -5794,30 +5857,47 @@ en_neighbor_table_notify_run(struct engine_node > *node OVS_UNUSED, > > return state; > > } > > > > +struct ed_type_neighbor_exchange { > > + /* Contains 'struct evpn_remote_vtep'. */ > > + struct hmap remote_vteps; > > +}; > > + > > static void * > > en_neighbor_exchange_init(struct engine_node *node OVS_UNUSED, > > struct engine_arg *arg OVS_UNUSED) > > { > > - return NULL; > > + struct ed_type_neighbor_exchange *data = xmalloc(sizeof *data); > > + *data = (struct ed_type_neighbor_exchange) { > > + .remote_vteps = HMAP_INITIALIZER(&data->remote_vteps), > > + }; > > + > > + return data; > > } > > > > static void > > -en_neighbor_exchange_cleanup(void *data OVS_UNUSED) > > +en_neighbor_exchange_cleanup(void *data_) > > { > > + struct ed_type_neighbor_exchange *data = data_; > > + evpn_remote_vteps_clear(&data->remote_vteps); > > + hmap_destroy(&data->remote_vteps); > > } > > > > static enum engine_node_state > > -en_neighbor_exchange_run(struct engine_node *node, void *data > OVS_UNUSED) > > +en_neighbor_exchange_run(struct engine_node *node, void *data_) > > { > > + struct ed_type_neighbor_exchange *data = data_; > > const struct ed_type_neighbor *neighbor_data = > > engine_get_input_data("neighbor", node); > > > > + evpn_remote_vteps_clear(&data->remote_vteps); > > + > > struct neighbor_exchange_ctx_in n_ctx_in = { > > .monitored_interfaces = &neighbor_data->monitored_interfaces, > > }; > > struct neighbor_exchange_ctx_out n_ctx_out = { > > .neighbor_table_watches = > > HMAP_INITIALIZER(&n_ctx_out.neighbor_table_watches), > > + .remote_vteps = &data->remote_vteps, > > }; > > > > neighbor_exchange_run(&n_ctx_in, &n_ctx_out); > > @@ -6402,6 +6482,10 @@ main(int argc, char *argv[]) > > engine_add_input(&en_garp_rarp, &en_runtime_data, > > garp_rarp_runtime_data_handler); > > > > + engine_add_input(&en_neighbor, &en_runtime_data, > > + neighbor_runtime_data_handler); > > + engine_add_input(&en_neighbor, &en_sb_datapath_binding, > > + neighbor_sb_datapath_binding_handler); > > engine_add_input(&en_neighbor_exchange, &en_neighbor, NULL); > > engine_add_input(&en_neighbor_exchange, &en_host_if_monitor, NULL); > > engine_add_input(&en_neighbor_exchange, &en_neighbor_table_notify, > NULL); > > @@ -6487,6 +6571,8 @@ main(int argc, char *argv[]) > > engine_get_internal_data(&en_lb_data); > > struct mac_cache_data *mac_cache_data = > > engine_get_internal_data(&en_mac_cache); > > + struct ed_type_neighbor_exchange *ne_data = > > + engine_get_internal_data(&en_neighbor_exchange); > > > > ofctrl_init(&lflow_output_data->group_table, > > &lflow_output_data->meter_table); > > @@ -6503,6 +6589,10 @@ main(int argc, char *argv[]) > > ct_zone_list, > > &ct_zones_data->ctx.current); > > > > + unixctl_command_register("evpn/remote-vtep-list", "", 0, 0, > > + evpn_remote_vtep_list, > > + &ne_data->remote_vteps); > > + > > struct pending_pkt pending_pkt = { .conn = NULL }; > > unixctl_command_register("inject-pkt", "MICROFLOW", 1, 1, > inject_pkt, > > &pending_pkt); > > diff --git a/lib/ovn-util.c b/lib/ovn-util.c > > index d7e236059..c12de4da9 100644 > > --- a/lib/ovn-util.c > > +++ b/lib/ovn-util.c > > @@ -1484,3 +1484,9 @@ ovn_mirror_port_name(const char *datapath_name, > > { > > return xasprintf("mp-%s-%s", datapath_name, port_name); > > } > > + > > +bool > > +ovn_is_valid_vni(int64_t vni) > > +{ > > + return vni >= 0 && (vni <= (1 << 24) - 1); > > +} > > diff --git a/lib/ovn-util.h b/lib/ovn-util.h > > index c05bfc53b..f31eba344 100644 > > --- a/lib/ovn-util.h > > +++ b/lib/ovn-util.h > > @@ -500,6 +500,8 @@ bool find_prefix_in_set(const struct in6_addr > *prefix, unsigned int plen, > > > > void ovn_debug_commands_register(void); > > > > +bool ovn_is_valid_vni(int64_t vni); > > + > > const struct sbrec_port_binding *lport_lookup_by_name( > > struct ovsdb_idl_index *sbrec_port_binding_by_name, > > const char *name); > > Regards, > Dumitru > > Everything else should be addressed in v2. Thanks, Ales _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev