Accept FDB entries with nexthop group ID (nh_id) in ne_is_valid_static_fdb(), alongside the existing single-VTEP-IP entries. Thread nh_id through evpn_static_entry so it is available for downstream resolution.
Assisted-by: Claude Opus 4.6, Claude Code Signed-off-by: Ales Musil <[email protected]> --- controller/neighbor-exchange-netlink.c | 8 ++++--- controller/neighbor-exchange.c | 31 ++++++++++++++------------ controller/neighbor-exchange.h | 5 ++++- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/controller/neighbor-exchange-netlink.c b/controller/neighbor-exchange-netlink.c index 9eecf9f5b..5ea8aeb58 100644 --- a/controller/neighbor-exchange-netlink.c +++ b/controller/neighbor-exchange-netlink.c @@ -193,13 +193,15 @@ ne_is_valid_remote_vtep(struct ne_nl_received_neigh *ne) return false; } -/* OVN expects that the FDB entry has an IP address (that of the remote VTEP), - * has MAC address and the entry is marked as "extern learned". */ +/* OVN expects that the FDB entry has a MAC address, the entry is marked as + * "extern learned", and either has an IP address (that of the remote VTEP) + * or a nexthop group ID (for ECMP/multi-homed entries). */ bool ne_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; + (ipv6_addr_is_set(&ne->addr) || ne->nh_id) && + ne->flags & NTF_EXT_LEARNED; } /* OVN expects that the ARP entry has an IP address, a MAC address, diff --git a/controller/neighbor-exchange.c b/controller/neighbor-exchange.c index 47e757712..43626cc21 100644 --- a/controller/neighbor-exchange.c +++ b/controller/neighbor-exchange.c @@ -39,13 +39,13 @@ static struct evpn_remote_vtep *evpn_remote_vtep_find( uint16_t port, uint32_t vni); static void evpn_static_entry_add(struct hmap *static_entries, struct eth_addr mac, struct in6_addr ip, - uint32_t vni); + uint32_t vni, uint32_t nh_id); static struct evpn_static_entry *evpn_static_entry_find( const struct hmap *static_entries, struct eth_addr mac, - struct in6_addr ip, uint32_t vni); + struct in6_addr ip, uint32_t vni, uint32_t nh_id); static uint32_t evpn_static_entry_hash(const struct eth_addr *mac, const struct in6_addr *ip, - uint32_t vni); + uint32_t vni, uint32_t nh_id); /* Last neighbor_exchange netlink operation. */ static int neighbor_exchange_nl_status; @@ -100,10 +100,10 @@ neighbor_exchange_run(const struct neighbor_exchange_ctx_in *n_ctx_in, if (ne_is_valid_static_arp(ne)) { if (!evpn_static_entry_find(n_ctx_out->static_arps, ne->lladdr, ne->addr, - nim->vni)) { + nim->vni, 0)) { evpn_static_entry_add(n_ctx_out->static_arps, ne->lladdr, ne->addr, - nim->vni); + nim->vni, 0); } } } @@ -122,10 +122,10 @@ neighbor_exchange_run(const struct neighbor_exchange_ctx_in *n_ctx_in, if (ne_is_valid_static_fdb(ne)) { if (!evpn_static_entry_find(n_ctx_out->static_fdbs, ne->lladdr, ne->addr, - nim->vni)) { + nim->vni, ne->nh_id)) { evpn_static_entry_add(n_ctx_out->static_fdbs, ne->lladdr, ne->addr, - nim->vni); + nim->vni, ne->nh_id); } } } @@ -230,30 +230,32 @@ evpn_remote_vtep_hash(const struct in6_addr *ip, uint16_t port, static void evpn_static_entry_add(struct hmap *static_entries, struct eth_addr mac, - struct in6_addr ip, uint32_t vni) + struct in6_addr ip, uint32_t vni, uint32_t nh_id) { struct evpn_static_entry *e = xmalloc(sizeof *e); *e = (struct evpn_static_entry) { .mac = mac, .ip = ip, .vni = vni, + .nh_id = nh_id, }; hmap_insert(static_entries, &e->hmap_node, - evpn_static_entry_hash(&mac, &ip, vni)); + evpn_static_entry_hash(&mac, &ip, vni, nh_id)); } static struct evpn_static_entry * evpn_static_entry_find(const struct hmap *static_entries, struct eth_addr mac, - struct in6_addr ip, uint32_t vni) + struct in6_addr ip, uint32_t vni, uint32_t nh_id) { - uint32_t hash = evpn_static_entry_hash(&mac, &ip, vni); + uint32_t hash = evpn_static_entry_hash(&mac, &ip, vni, nh_id); struct evpn_static_entry *e; HMAP_FOR_EACH_WITH_HASH (e, hmap_node, hash, static_entries) { if (eth_addr_equals(e->mac, mac) && ipv6_addr_equals(&e->ip, &ip) && - e->vni == vni) { + e->vni == vni && + e->nh_id == nh_id) { return e; } } @@ -263,12 +265,13 @@ evpn_static_entry_find(const struct hmap *static_entries, struct eth_addr mac, static uint32_t evpn_static_entry_hash(const struct eth_addr *mac, const struct in6_addr *ip, - uint32_t vni) + uint32_t vni, uint32_t nh_id) { uint32_t hash = 0; hash = hash_bytes(mac, sizeof *mac, hash); hash = hash_add_in6_addr(hash, ip); hash = hash_add(hash, vni); + hash = hash_add(hash, nh_id); - return hash_finish(hash, 26); + return hash_finish(hash, 30); } diff --git a/controller/neighbor-exchange.h b/controller/neighbor-exchange.h index 32c87a8ab..456ff23df 100644 --- a/controller/neighbor-exchange.h +++ b/controller/neighbor-exchange.h @@ -56,10 +56,13 @@ struct evpn_static_entry { struct hmap_node hmap_node; /* MAC address of the remote workload. */ struct eth_addr mac; - /* Destination ip of the remote tunnel or remote IP. */ + /* Destination IP of the remote tunnel or remote IP. + * Zero if nh_id is set. */ struct in6_addr ip; /* VNI of the VTEP. */ uint32_t vni; + /* Nexthop group ID for ECMP/multi-homed entries, 0 if ip is set. */ + uint32_t nh_id; }; void neighbor_exchange_run(const struct neighbor_exchange_ctx_in *, -- 2.53.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
