The FDB collector for the EVPN advertise interface only iterates the
Logical_Switch's Port_Bindings, picking MACs out of pb->mac.  That works
for VIFs and router ports, where the MAC of interest is always a
Port_Binding address, but it skips MACs that are only known via
Advertised_MAC_Binding (for example, the external_mac of a distributed
dnat_and_snat NAT entry, i.e. a floating IP).

Without the MAC in the local FDB, FRR cannot match the corresponding
ip neigh entry (which is already programmed by the IP-mode collector)
to a local MAC, and therefore does not emit a Type-2 MAC+IP route for
the floating IP -- only direct VIF and router-port advertisements work.

Extend neighbor_collect_mac_to_advertise() so that, after walking the
Port_Bindings on the Logical_Switch, it also iterates the
Advertised_MAC_Binding rows attached to the same datapath.  The same
chassis-residency filter (via neighbor_get_relevant_port_binding) is
reused so the MAC is only injected on the chassis that owns the
referenced port.

This is the controller-side counterpart of the ovn-northd change in
"northd: Advertise distributed NAT IPs over EVPN."

Reported-by: Chanyeol Yoon <[email protected]>
Suggested-by: Ales Musil <[email protected]>
Signed-off-by: Chanyeol Yoon <[email protected]>
---
 controller/neighbor.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/controller/neighbor.c b/controller/neighbor.c
index 72fabe205..8bbd8e224 100644
--- a/controller/neighbor.c
+++ b/controller/neighbor.c
@@ -301,6 +301,44 @@ neighbor_collect_mac_to_advertise(const struct 
neighbor_ctx_in *n_ctx_in,
     }
 
     sbrec_port_binding_index_destroy_row(target);
+
+    /* Some MACs need to be advertised over EVPN even though they are not the
+     * address of any port_binding on this Logical Switch (for example, the
+     * external_mac of a distributed dnat_and_snat NAT entry / floating IP).
+     * For those, ovn-northd populates the Advertised_MAC_Binding table on
+     * this Logical Switch and we inject them into the FDB here. */
+    struct sbrec_advertised_mac_binding *amb_target =
+        sbrec_advertised_mac_binding_index_init_row(n_ctx_in->sbrec_amb_by_dp);
+    sbrec_advertised_mac_binding_index_set_datapath(amb_target, dp);
+
+    const struct sbrec_advertised_mac_binding *adv_mb;
+    SBREC_ADVERTISED_MAC_BINDING_FOR_EACH_EQUAL (adv_mb, amb_target,
+                                                 n_ctx_in->sbrec_amb_by_dp) {
+        if (!adv_mb->logical_port) {
+            continue;
+        }
+
+        const struct sbrec_port_binding *pb =
+            neighbor_get_relevant_port_binding(n_ctx_in->sbrec_pb_by_name,
+                                               adv_mb->logical_port);
+        if (!lport_pb_is_chassis_resident(n_ctx_in->chassis, pb)) {
+            continue;
+        }
+
+        struct eth_addr ea;
+        char *err = str_to_mac(adv_mb->mac, &ea);
+        if (err) {
+            free(err);
+            continue;
+        }
+
+        if (!advertise_neigh_find(neighbors, ea, &in6addr_any)) {
+            advertise_neigh_add(neighbors, ea, in6addr_any);
+        }
+        sset_add(advertised_pbs, pb->logical_port);
+    }
+
+    sbrec_advertised_mac_binding_index_destroy_row(amb_target);
 }
 
 static void
-- 
2.54.0 (Apple Git-156)

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to