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

Reply via email to