On Mon, Jun 22, 2026 at 2:27 PM Ales Musil <[email protected]> wrote:
> > > On Sun, Jun 21, 2026 at 12:47 PM Chanyeol Yoon <[email protected]> wrote: > >> When a Logical Router has a 'dnat_and_snat' NAT entry with both >> 'external_mac' and 'logical_port' set (a distributed floating IP), its >> external IP/MAC are not advertised over BGP-EVPN. Only ports directly >> attached to the EVPN-enabled provider Logical Switch are covered, so >> floating IPs (a common CMS pattern, e.g. OpenStack Neutron with >> distributed FIPs) stay unreachable from EVPN peers. >> >> Populate the SB Advertised_MAC_Binding for the provider Logical Switch >> that carries the NAT's distributed gateway port, using the NAT's >> 'external_ip' and 'external_mac'. ovn-controller then programs those >> into the EVPN advertise interface so the floating IPs are emitted as >> EVPN Type-2 MAC+IP routes on the chassis that hosts the workload. >> >> This is gated by a new 'nat' token of the provider Logical Switch >> 'dynamic-routing-redistribute' option, independent of the existing >> 'ip' token: 'ip' keeps advertising VIF and router-port addresses while >> 'nat' opts in to floating IPs. It mirrors the 'nat' token of the >> Logical_Router 'dynamic-routing-redistribute' option, which advertises >> the same NAT entries as EVPN Type-5 routes. >> >> A new 'type' column on the Advertised_MAC_Binding table records the >> origin of each row ('ip' for a port address, 'nat' for a floating IP) >> so that ovn-controller can decide whether to advertise it based on the >> datapath's redistribute tokens. >> >> en-advertised-mac-binding-sync gets a northd change handler that >> recomputes only when a switch was created or deleted, or a router's >> NATs changed (via the northd tracked data); lr_nat is read purely as >> input data. >> >> Suggested-by: Ales Musil <[email protected]> >> Signed-off-by: Chanyeol Yoon <[email protected]> >> --- >> > > Hi Chanyeol, > > thank you for the v6. I have a few comments down below. > > .../topics/dynamic-routing/architecture.rst | 12 ++ >> NEWS | 6 + >> lib/ovn-util.c | 3 + >> lib/ovn-util.h | 3 +- >> northd/en-advertised-route-sync.c | 142 ++++++++++++++++-- >> northd/en-advertised-route-sync.h | 3 + >> northd/inc-proc-northd.c | 7 +- >> ovn-nb.xml | 27 ++++ >> ovn-sb.ovsschema | 6 +- >> ovn-sb.xml | 19 +++ >> tests/ovn-inc-proc-graph-dump.at | 3 +- >> tests/ovn-northd.at | 98 ++++++++++++ >> 12 files changed, 312 insertions(+), 17 deletions(-) >> >> diff --git a/Documentation/topics/dynamic-routing/architecture.rst >> b/Documentation/topics/dynamic-routing/architecture.rst >> index c517fe085..49af3c8fb 100644 >> --- a/Documentation/topics/dynamic-routing/architecture.rst >> +++ b/Documentation/topics/dynamic-routing/architecture.rst >> @@ -671,6 +671,18 @@ external network fabric. Each record includes: >> - ``ip`` --- The IP address to announce. >> - ``mac`` --- The MAC address to announce. >> >> +For each EVPN-enabled logical switch, ``ovn-northd`` populates the >> +table from the following sources, each gated by a token of the >> +``dynamic-routing-redistribute`` option on the logical switch: >> + >> +- With ``ip``: the MAC/IP addresses of regular VIF ports on the logical >> + switch, and the MAC/IP addresses of router ports peered with it. >> +- With ``nat``: the ``external_ip``/``external_mac`` of any distributed >> + ``dnat_and_snat`` NAT entry on a router whose distributed gateway >> + port is attached to the logical switch. This allows floating IPs >> + to be advertised as EVPN Type-2 routes alongside directly attached >> + workloads. The two tokens are independent and may be combined. >> + >> ``ovn-controller`` reads these records and installs the corresponding >> static FDB and neighbor entries on the appropriate kernel interfaces, >> making them available to the routing daemon for EVPN advertisement. >> diff --git a/NEWS b/NEWS >> index d426d671a..9796ce5f0 100644 >> --- a/NEWS >> +++ b/NEWS >> @@ -21,6 +21,12 @@ Post v26.03.0 >> generates proxy-reply flows using a dedicated side table >> and the new chk_evpn_arp() action, preventing unnecessary >> flooding to remote VTEPs. >> + * EVPN: distributed dnat_and_snat NAT entries (e.g. floating IPs) >> + are now populated in the SB Advertised_MAC_Binding table on the >> + provider logical switch that carries the distributed gateway >> + port, so that they can be advertised as EVPN Type-2 routes. This >> + is gated on a new "nat" token of the Logical_Switch >> + "dynamic-routing-redistribute" option, independent of "ip". >> - Added "override-connected" option to Logical Router Static Routes >> to mark >> static routes as higher-priority than connected routes, which in >> turn led >> to changes in administrative distance for specific route types. >> Please see >> diff --git a/lib/ovn-util.c b/lib/ovn-util.c >> index de65208f6..2fb23c536 100644 >> --- a/lib/ovn-util.c >> +++ b/lib/ovn-util.c >> @@ -1754,6 +1754,9 @@ parse_neigh_dynamic_redistribute(const struct smap >> *options) >> if (!strcmp(token, "ip")) { >> mode |= NRM_IP; >> } >> + if (!strcmp(token, "nat")) { >> + mode |= NRM_NAT; >> + } >> } >> free(tokstr); >> >> diff --git a/lib/ovn-util.h b/lib/ovn-util.h >> index 4d1761dc4..8044a9df4 100644 >> --- a/lib/ovn-util.h >> +++ b/lib/ovn-util.h >> @@ -796,7 +796,8 @@ char *normalize_addr_str(const char *orig_addr); >> >> #define NEIGH_REDISTRIBUTE_MODES \ >> NEIGH_REDISTRIBUTE_MODE(FDB, 0) \ >> - NEIGH_REDISTRIBUTE_MODE(IP, 1) >> + NEIGH_REDISTRIBUTE_MODE(IP, 1) \ >> + NEIGH_REDISTRIBUTE_MODE(NAT, 2) >> >> enum neigh_redistribute_mode_bits { >> #define NEIGH_REDISTRIBUTE_MODE(PROTOCOL, BIT) NRM_##PROTOCOL##_BIT = >> BIT, >> diff --git a/northd/en-advertised-route-sync.c >> b/northd/en-advertised-route-sync.c >> index 4a8d13232..589b73b98 100644 >> --- a/northd/en-advertised-route-sync.c >> +++ b/northd/en-advertised-route-sync.c >> @@ -819,6 +819,8 @@ struct advertised_mac_binding { >> >> char *ip; >> char *mac; >> + /* Origin of the binding: "ip" (port address) or "nat" (floating >> IP). */ >> + const char *type; >> }; >> >> static bool >> @@ -833,6 +835,18 @@ evpn_ip_redistribution_enabled(const struct >> ovn_datapath *od) >> return nrm_mode_IP_is_set(mode); >> } >> >> +static bool >> +evpn_nat_redistribution_enabled(const struct ovn_datapath *od) >> +{ >> + if (!od->has_evpn_vni) { >> + return false; >> + } >> + >> + enum neigh_redistribute_mode mode = >> + parse_neigh_dynamic_redistribute(&od->nbs->other_config); >> + return nrm_mode_NAT_is_set(mode); >> +} >> + >> static uint32_t >> advertised_mac_binding_get_hash(const struct sbrec_datapath_binding *dp, >> const struct sbrec_port_binding *sb, >> @@ -869,13 +883,15 @@ static void >> advertised_mac_binding_entry_add(struct hmap *map, >> const struct sbrec_datapath_binding *dp, >> const struct sbrec_port_binding *sb, >> - const char *ip, const char *mac) >> + const char *ip, const char *mac, >> + const char *type) >> { >> struct advertised_mac_binding *e = xmalloc(sizeof *e); >> e->ip = xstrdup(ip); >> e->mac = xstrdup(mac); >> e->sb = sb; >> e->dp = dp; >> + e->type = type; >> >> uint32_t hash = advertised_mac_binding_get_hash(dp, sb, ip, mac); >> hmap_insert(map, &e->hmap_node, hash); >> @@ -890,22 +906,23 @@ advertised_mac_binding_entry_destroy(struct >> advertised_mac_binding *e) >> } >> >> static void >> -advertised_mac_binding_add(struct hmap *map, >> - const struct sbrec_datapath_binding *dp, >> - const struct sbrec_port_binding *sb, >> - struct lport_addresses *addr) >> +advertised_mac_binding_add_with_mac(struct hmap *map, >> + const struct sbrec_datapath_binding >> *dp, >> + const struct sbrec_port_binding *sb, >> + const struct lport_addresses *addr, >> + const char *mac, const char *type) >> { >> - if (!addr) { >> + if (!addr || !mac) { >> return; >> } >> >> for (size_t i = 0; i < addr->n_ipv4_addrs; i++) { >> if (!advertised_mac_binding_entry_find(map, dp, sb, >> >> addr->ipv4_addrs[i].addr_s, >> - addr->ea_s)) { >> + mac)) { >> advertised_mac_binding_entry_add(map, dp, sb, >> addr->ipv4_addrs[i].addr_s, >> - addr->ea_s); >> + mac, type); >> } >> } >> >> @@ -916,14 +933,27 @@ advertised_mac_binding_add(struct hmap *map, >> >> if (!advertised_mac_binding_entry_find(map, dp, sb, >> >> addr->ipv6_addrs[i].addr_s, >> - addr->ea_s)) { >> + mac)) { >> advertised_mac_binding_entry_add(map, dp, sb, >> addr->ipv6_addrs[i].addr_s, >> - addr->ea_s); >> + mac, type); >> } >> } >> } >> >> +static void >> +advertised_mac_binding_add(struct hmap *map, >> + const struct sbrec_datapath_binding *dp, >> + const struct sbrec_port_binding *sb, >> + struct lport_addresses *addr) >> +{ >> + if (!addr) { >> + return; >> + } >> + >> + advertised_mac_binding_add_with_mac(map, dp, sb, addr, addr->ea_s, >> "ip"); >> +} >> + >> static void >> build_advertised_mac_binding(const struct ovn_datapath *od, struct hmap >> *map) >> { >> @@ -956,6 +986,57 @@ build_advertised_mac_binding(const struct >> ovn_datapath *od, struct hmap *map) >> } >> } >> >> +/* Advertise distributed dnat_and_snat NAT entries (e.g. floating IPs) >> over >> + * EVPN. The advertisement is attached to the provider Logical Switch >> that >> + * carries the NAT's distributed gateway port, provided that LS has NAT >> + * redistribution enabled via 'dynamic-routing-redistribute=nat'. */ >> +static void >> +build_advertised_mac_binding_lr(const struct ovn_datapath *od, >> + const struct lr_nat_table *lr_nats, >> + struct hmap *map) >> +{ >> + ovs_assert(od->nbr); >> + >> + const struct lr_nat_record *lrnat_rec = >> + lr_nat_table_find_by_uuid(lr_nats, od->nbr->header_.uuid); >> + if (!lrnat_rec) { >> + return; >> + } >> + >> + for (size_t i = 0; i < lrnat_rec->n_nat_entries; i++) { >> + const struct ovn_nat *nat_entry = &lrnat_rec->nat_entries[i]; >> + const struct nbrec_nat *nat = nat_entry->nb; >> + >> + if (!nat_entry->is_valid || !nat_entry->is_distributed || >> + nat_entry->type != DNAT_AND_SNAT) { >> + continue; >> + } >> + >> + if (!nat->external_mac) { >> + continue; >> + } >> + >> + if (!smap_get_bool(&nat->options, "dynamic-routing-advertise", >> true)) { >> + continue; >> + } >> + >> + const struct ovn_port *dgp = nat_entry->l3dgw_port; >> + if (!dgp || !dgp->peer || !dgp->peer->sb || !dgp->peer->od) { >> + continue; >> + } >> + >> + const struct ovn_datapath *peer_od = dgp->peer->od; >> + if (!peer_od->nbs || !evpn_nat_redistribution_enabled(peer_od)) { >> + continue; >> + } >> + >> + advertised_mac_binding_add_with_mac(map, peer_od->sdp->sb_dp, >> + dgp->peer->sb, >> + &nat_entry->ext_addrs, >> + nat->external_mac, "nat"); >> + } >> +} >> + >> void * >> en_advertised_mac_binding_sync_init(struct engine_node *node OVS_UNUSED, >> struct engine_arg *arg OVS_UNUSED) >> @@ -970,6 +1051,8 @@ en_advertised_mac_binding_sync_run(struct >> engine_node *node, >> struct northd_data *northd_data = engine_get_input_data("northd", >> node); >> const struct sbrec_advertised_mac_binding_table *sbrec_adv_mb_table = >> EN_OVSDB_GET(engine_get_input("SB_advertised_mac_binding", >> node)); >> + struct ed_type_lr_nat_data *lr_nat_data = >> + engine_get_input_data("lr_nat", node); >> const struct engine_context *eng_ctx = engine_get_context(); >> >> struct hmap advertised_mac_binding_map = >> @@ -979,6 +1062,10 @@ en_advertised_mac_binding_sync_run(struct >> engine_node *node, >> HMAP_FOR_EACH (od, key_node, &northd_data->ls_datapaths.datapaths) { >> build_advertised_mac_binding(od, &advertised_mac_binding_map); >> } >> + HMAP_FOR_EACH (od, key_node, &northd_data->lr_datapaths.datapaths) { >> + build_advertised_mac_binding_lr(od, &lr_nat_data->lr_nats, >> + &advertised_mac_binding_map); >> + } >> >> struct advertised_mac_binding *e; >> const struct sbrec_advertised_mac_binding *sb_adv_mb; >> @@ -991,6 +1078,9 @@ en_advertised_mac_binding_sync_run(struct >> engine_node *node, >> if (!e) { >> sbrec_advertised_mac_binding_delete(sb_adv_mb); >> } else { >> + if (!sb_adv_mb->type || strcmp(sb_adv_mb->type, e->type)) { >> + sbrec_advertised_mac_binding_set_type(sb_adv_mb, >> e->type); >> + } >> > > I would skip this update, it will converge over time on its own. > If the check in ovn-controller is resilient to NULL (which in the > current form it is), it should be fine. > > >> hmap_remove(&advertised_mac_binding_map, &e->hmap_node); >> advertised_mac_binding_entry_destroy(e); >> } >> @@ -1003,6 +1093,7 @@ en_advertised_mac_binding_sync_run(struct >> engine_node *node, >> sbrec_advertised_mac_binding_set_logical_port(sb_adv_mb, e->sb); >> sbrec_advertised_mac_binding_set_ip(sb_adv_mb, e->ip); >> sbrec_advertised_mac_binding_set_mac(sb_adv_mb, e->mac); >> + sbrec_advertised_mac_binding_set_type(sb_adv_mb, e->type); >> advertised_mac_binding_entry_destroy(e); >> } >> >> @@ -1022,3 +1113,34 @@ northd_output_advertised_mac_binding_sync_handler( >> { >> return EN_HANDLED_UPDATED; >> } >> + >> +enum engine_input_handler_result >> +advertised_mac_binding_sync_northd_change_handler(struct engine_node >> *node, >> + void *data OVS_UNUSED) >> +{ >> + struct northd_data *northd_data = engine_get_input_data("northd", >> node); >> + struct northd_tracked_data *trk_data = &northd_data->trk_data; >> + >> + /* Without tracked data northd did a full recompute (for example a >> + * Logical_Switch 'other_config' change that toggles the EVPN >> settings), >> + * so the advertised set must be re-evaluated. */ >> + if (!northd_has_tracked_data(trk_data)) { >> + return EN_UNHANDLED; >> + } >> + >> + /* A created or deleted Logical_Switch may have EVPN redistribution >> + * enabled and contribute advertised MAC bindings. */ >> + if (!hmapx_is_empty(&trk_data->trk_switches.crupdated) || >> + !hmapx_is_empty(&trk_data->trk_switches.deleted)) { >> + return EN_UNHANDLED; >> + } >> + >> + /* The distributed dnat_and_snat NAT entries (floating IPs) of a >> Logical >> + * Router are advertised on its peer provider Logical Switch, so a >> change >> + * to a router's NATs must re-evaluate the advertised MAC bindings. >> */ >> + if (!hmapx_is_empty(&trk_data->trk_nat_lrs)) { >> + return EN_UNHANDLED; >> + } >> + >> + return EN_HANDLED_UNCHANGED; >> +} >> > > I thought we had agreed that this handler would be a separate > commit. Include the test that exercises the broken behavior. > > diff --git a/northd/en-advertised-route-sync.h >> b/northd/en-advertised-route-sync.h >> index 71cd417de..3bb48fa0a 100644 >> --- a/northd/en-advertised-route-sync.h >> +++ b/northd/en-advertised-route-sync.h >> @@ -52,4 +52,7 @@ en_advertised_mac_binding_sync_run(struct engine_node >> *, void *data); >> enum engine_input_handler_result >> northd_output_advertised_mac_binding_sync_handler(struct engine_node *, >> void *data); >> +enum engine_input_handler_result >> +advertised_mac_binding_sync_northd_change_handler(struct engine_node >> *node, >> + void *data); >> #endif /* EN_ADVERTISED_ROUTE_SYNC_H */ >> diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c >> index a2b464411..c5de647aa 100644 >> --- a/northd/inc-proc-northd.c >> +++ b/northd/inc-proc-northd.c >> @@ -364,10 +364,11 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, >> NULL); >> engine_add_input(&en_advertised_mac_binding_sync, >> &en_sb_advertised_mac_binding, NULL); >> - /* No need for an explicit handler for northd changes. >> - * We do need to access en_northd (input) data, i.e., to >> - * lookup OVN ports. */ >> engine_add_input(&en_advertised_mac_binding_sync, &en_northd, >> + advertised_mac_binding_sync_northd_change_handler); >> + /* The lr_nat data is only read in run(); the recompute is triggered >> via >> + * the northd tracked NAT data (see the handler above). */ >> + engine_add_input(&en_advertised_mac_binding_sync, &en_lr_nat, >> engine_noop_handler); >> >> engine_add_input(&en_learned_route_sync, &en_sb_learned_route, >> diff --git a/ovn-nb.xml b/ovn-nb.xml >> index 15fb1d7e8..11b8a4362 100644 >> --- a/ovn-nb.xml >> +++ b/ovn-nb.xml >> @@ -1032,6 +1032,20 @@ >> all IPs/MACs bindings that are local to the chassis. This >> applies to >> VIFs and router ports. >> </p> >> + >> + <p> >> + If <code>nat</code> is specified then the external IP/MAC of >> any >> + distributed <code>dnat_and_snat</code> NAT entry (for example a >> + floating IP) whose distributed gateway port is attached to this >> + logical switch is advertised as an EVPN Type-2 route, using the >> + NAT's <ref column="external_mac" table="NAT"/>. This is >> independent >> + of <code>ip</code>: enabling <code>ip</code> alone does not >> advertise >> + floating IPs, and enabling <code>nat</code> alone does not >> advertise >> + VIF or router-port addresses. This mirrors the >> <code>nat</code> >> + token of <ref column="options" >> key="dynamic-routing-redistribute" >> + table="Logical_Router"/>, which advertises the same NAT >> entries as >> + EVPN Type-5 routes. >> + </p> >> </column> >> </group> >> >> @@ -5476,6 +5490,19 @@ or >> used by the CMS to enable/disable the advertisement of the current >> NAT >> external IP via the <ref table="Advertised_Route" >> db="OVN_Southbound"/> >> table. Default: <code>true</code>. >> + >> + <p> >> + For a distributed <code>dnat_and_snat</code> entry (a floating >> IP, >> + with both <ref column="external_mac"/> and <ref >> column="logical_port"/> >> + set) this also controls the EVPN Type-2 advertisement: when the >> + provider <ref table="Logical_Switch"/> that carries the NAT's >> + distributed gateway port has <code>nat</code> set in its >> + <ref column="other_config" key="dynamic-routing-redistribute" >> + table="Logical_Switch"/>, the external IP/MAC are published in >> the >> + <ref table="Advertised_MAC_Binding" db="OVN_Southbound"/> table. >> + Setting this option to <code>false</code> opts the individual >> floating >> + IP out of that advertisement as well. >> + </p> >> </column> >> >> <group title="Common Columns"> >> diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema >> index d38992ad8..cf3a5f536 100644 >> --- a/ovn-sb.ovsschema >> +++ b/ovn-sb.ovsschema >> @@ -1,7 +1,7 @@ >> { >> "name": "OVN_Southbound", >> - "version": "21.9.0", >> - "cksum": "3029208442 36713", >> + "version": "21.10.0", >> + "cksum": "1797819836 36851", >> "tables": { >> "SB_Global": { >> "columns": { >> @@ -707,6 +707,8 @@ >> "refType": "strong"}}}, >> "ip": {"type": "string"}, >> "mac": {"type": "string"}, >> + "type": {"type": {"key": {"type": "string", >> + "enum": ["set", ["ip", >> "nat"]]}}}, >> > > That's my bad but I forgot to mention that we have > to be careful about upgrades. We need to make this optional > see the type in Datapath_Binding table. ("min": 0, "max": 1). > > This also means that the old values will have type=NULL > after upgrade so we need to take that into account during > the type check (which seems to be the case already). > > "external_ids": { >> "type": {"key": "string", "value": "string", >> "min": 0, "max": "unlimited"}}}, >> diff --git a/ovn-sb.xml b/ovn-sb.xml >> index 9b453a372..c002a034a 100644 >> --- a/ovn-sb.xml >> +++ b/ovn-sb.xml >> @@ -5578,6 +5578,25 @@ tcp.flags = RST; >> Announced mac address. >> </column> >> >> + <column name="type"> >> + The origin of this binding, used by <code>ovn-controller</code> to >> decide >> + whether to advertise it based on the datapath's >> + <code>dynamic-routing-redistribute</code> tokens: >> + <ul> >> + <li> >> + <code>ip</code>: the address of a port attached to the >> + EVPN-enabled <code>OVN_Northbound.Logical_Switch</code> (a VIF >> or a >> + router port). Advertised when the <code>ip</code> token is set. >> + </li> >> + <li> >> + <code>nat</code>: the external IP/MAC of a distributed >> + <code>dnat_and_snat</code> NAT entry (a floating IP) whose >> + distributed gateway port is peered with this Logical Switch. >> + Advertised when the <code>nat</code> token is set. >> + </li> >> + </ul> >> + </column> >> + >> <column name="external_ids"> >> See <em>External IDs</em> at the beginning of this document. >> </column> >> diff --git a/tests/ovn-inc-proc-graph-dump.at b/tests/ >> ovn-inc-proc-graph-dump.at >> index 3750339d0..e68d9be96 100644 >> --- a/tests/ovn-inc-proc-graph-dump.at >> +++ b/tests/ovn-inc-proc-graph-dump.at >> @@ -229,7 +229,8 @@ digraph "Incremental-Processing-Engine" { >> advertised_mac_binding_sync [[style=filled, shape=box, >> fillcolor=white, label="advertised_mac_binding_sync"]]; >> SB_port_binding -> advertised_mac_binding_sync [[label=""]]; >> SB_advertised_mac_binding -> advertised_mac_binding_sync >> [[label=""]]; >> - northd -> advertised_mac_binding_sync >> [[label="engine_noop_handler"]]; >> + northd -> advertised_mac_binding_sync >> [[label="advertised_mac_binding_sync_northd_change_handler"]]; >> + lr_nat -> advertised_mac_binding_sync >> [[label="engine_noop_handler"]]; >> northd_output [[style=filled, shape=box, fillcolor=white, >> label="northd_output"]]; >> acl_id -> northd_output [[label="northd_output_acl_id_handler"]]; >> sync_from_sb -> northd_output [[label=""]]; >> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at >> index 4ef2c8946..25e98b628 100644 >> --- a/tests/ovn-northd.at >> +++ b/tests/ovn-northd.at >> @@ -20285,6 +20285,8 @@ ls_evpn_uuid=$(fetch_column Datapath_Binding >> _uuid external_ids:name=ls-evpn) >> >> check ovn-nbctl --wait=sb set logical_switch ls-evpn >> other_config:dynamic-routing-redistribute=ip >> check_row_count Advertised_MAC_Binding 1 ip=10.0.0.2 >> datapath=$ls_evpn_uuid mac='00\:00\:00\:00\:01\:00' >> +dnl Port-derived bindings are stamped with type=ip. >> +check_row_count Advertised_MAC_Binding 1 type=ip >> >> check ovn-nbctl lr-add lr \ >> -- lrp-add lr lrp 00:00:00:00:01:01 10.0.0.1/24 \ >> @@ -20309,6 +20311,102 @@ OVN_CLEANUP_NORTHD >> AT_CLEANUP >> ]) >> >> +OVN_FOR_EACH_NORTHD_NO_HV([ >> +AT_SETUP([LR EVPN Advertised_MAC_Binding sync for distributed NAT]) >> +ovn_start >> + >> +check ovn-sbctl chassis-add ch geneve 127.0.0.1 >> + >> +AS_BOX([Build topology: tenant LS, LR with DGP, EVPN-enabled provider >> LS]) >> +check ovn-nbctl ls-add ls-tenant >> \ >> + -- lsp-add ls-tenant vm1 >> \ >> + -- lsp-set-addresses vm1 "00:00:00:00:02:00 10.0.0.10" >> +check ovn-nbctl ls-add ls-evpn >> \ >> + -- set logical_switch ls-evpn other_config:dynamic-routing-vni=10 >> \ >> + -- set logical_switch ls-evpn >> other_config:dynamic-routing-redistribute=ip >> +dnl A provider logical switch has a localnet port; without it the DGP's >> +dnl peer gets a chassisredirect port and the NAT is not considered >> +dnl distributed (so floating IPs would never be advertised). >> +check ovn-nbctl lsp-add ls-evpn ln-evpn >> \ >> + -- lsp-set-type ln-evpn localnet >> \ >> + -- lsp-set-addresses ln-evpn unknown >> \ >> + -- lsp-set-options ln-evpn network_name=phys >> +check ovn-nbctl lr-add lr >> \ >> + -- lrp-add lr lrp-int 00:00:00:00:01:01 10.0.0.1/24 >> \ >> + -- lrp-add lr lrp-ext 00:00:00:00:01:02 172.16.0.1/24 >> \ >> + -- lrp-set-gateway-chassis lrp-ext ch >> \ >> + -- lsp-add ls-tenant ls-tenant-lrp >> \ >> + -- lsp-set-type ls-tenant-lrp router >> \ >> + -- lsp-set-addresses ls-tenant-lrp 00:00:00:00:01:01 >> \ >> + -- lsp-set-options ls-tenant-lrp router-port=lrp-int >> \ >> + -- lsp-add ls-evpn ls-evpn-lrp >> \ >> + -- lsp-set-type ls-evpn-lrp router >> \ >> + -- lsp-set-addresses ls-evpn-lrp 00:00:00:00:01:02 >> \ >> + -- lsp-set-options ls-evpn-lrp router-port=lrp-ext >> +check ovn-nbctl --wait=sb sync >> + >> +ls_evpn_uuid=$(fetch_column Datapath_Binding _uuid >> external_ids:name=ls-evpn) >> + >> +AS_BOX([Baseline: LRP MAC/IP advertised, no NAT yet]) >> +check_row_count Advertised_MAC_Binding 1 ip=172.16.0.1 >> datapath=$ls_evpn_uuid mac='00\:00\:00\:00\:01\:02' >> +check_row_count Advertised_MAC_Binding 1 >> + >> +AS_BOX([Non-distributed NATs are not advertised]) >> +check ovn-nbctl --wait=sb lr-nat-add lr snat 172.16.0.50 10.0.0.10 >> +check ovn-nbctl --wait=sb lr-nat-add lr dnat 172.16.0.51 10.0.0.10 >> +check_row_count Advertised_MAC_Binding 1 >> +check ovn-nbctl --wait=sb lr-nat-del lr snat 172.16.0.50 >> +check ovn-nbctl --wait=sb lr-nat-del lr dnat 172.16.0.51 >> + >> +AS_BOX([dnat_and_snat without external_mac is not advertised]) >> +check ovn-nbctl --wait=sb lr-nat-add lr dnat_and_snat 172.16.0.52 >> 10.0.0.10 >> +check_row_count Advertised_MAC_Binding 1 >> +check ovn-nbctl --wait=sb lr-nat-del lr dnat_and_snat 172.16.0.52 >> + >> +AS_BOX([Distributed FIP is not advertised with 'ip' alone (needs 'nat')]) >> +check ovn-nbctl --wait=sb lr-nat-add lr dnat_and_snat 172.16.0.100 >> 10.0.0.10 vm1 00:11:22:33:44:55 >> +check_row_count Advertised_MAC_Binding 0 ip=172.16.0.100 >> +check_row_count Advertised_MAC_Binding 1 >> + >> +AS_BOX([Adding the 'nat' token advertises the FIP]) >> +check ovn-nbctl --wait=sb set logical_switch ls-evpn >> other_config:dynamic-routing-redistribute=ip,nat >> +check_row_count Advertised_MAC_Binding 1 ip=172.16.0.100 >> datapath=$ls_evpn_uuid mac='00\:11\:22\:33\:44\:55' >> +check_row_count Advertised_MAC_Binding 2 >> +dnl The FIP binding is stamped with type=nat, the LRP one with type=ip. >> +check_row_count Advertised_MAC_Binding 1 ip=172.16.0.100 type=nat >> +check_row_count Advertised_MAC_Binding 1 ip=172.16.0.1 type=ip >> + >> +AS_BOX([Adding a second FIP yields a second advertised entry]) >> +check ovn-nbctl --wait=sb lsp-add ls-tenant vm2 >> \ >> + -- lsp-set-addresses vm2 "00:00:00:00:02:01 10.0.0.11" >> +check ovn-nbctl --wait=sb lr-nat-add lr dnat_and_snat 172.16.0.101 >> 10.0.0.11 vm2 00:11:22:33:44:66 >> +check_row_count Advertised_MAC_Binding 1 ip=172.16.0.101 >> datapath=$ls_evpn_uuid mac='00\:11\:22\:33\:44\:66' >> +check_row_count Advertised_MAC_Binding 3 >> + >> +AS_BOX([Deleting a NAT removes its advertised entry]) >> +check ovn-nbctl --wait=sb lr-nat-del lr dnat_and_snat 172.16.0.100 >> +check_row_count Advertised_MAC_Binding 0 ip=172.16.0.100 >> +check_row_count Advertised_MAC_Binding 2 >> + >> +AS_BOX(['nat' and 'ip' are independent: dropping 'nat' keeps the LRP >> entry]) >> +check ovn-nbctl --wait=sb set logical_switch ls-evpn >> other_config:dynamic-routing-redistribute=ip >> +check_row_count Advertised_MAC_Binding 0 ip=172.16.0.101 >> +check_row_count Advertised_MAC_Binding 1 ip=172.16.0.1 >> datapath=$ls_evpn_uuid mac='00\:00\:00\:00\:01\:02' >> +check_row_count Advertised_MAC_Binding 1 >> + >> +AS_BOX([Disabling EVPN on the provider LS removes all advertisements]) >> +check ovn-nbctl --wait=sb remove logical_switch ls-evpn other_config >> dynamic-routing-redistribute >> +check_row_count Advertised_MAC_Binding 0 >> + >> +AS_BOX([Re-enabling redistribute=ip,nat restores both LRP and FIP]) >> +check ovn-nbctl --wait=sb set logical_switch ls-evpn >> other_config:dynamic-routing-redistribute=ip,nat >> +check_row_count Advertised_MAC_Binding 1 ip=172.16.0.101 >> datapath=$ls_evpn_uuid mac='00\:11\:22\:33\:44\:66' >> +check_row_count Advertised_MAC_Binding 2 >> + >> +OVN_CLEANUP_NORTHD >> +AT_CLEANUP >> +]) >> + >> OVN_FOR_EACH_NORTHD_NO_HV([ >> AT_SETUP([IGMP northd crash]) >> ovn_start >> -- >> 2.54.0 (Apple Git-156) >> >> > Regards, > Ales > Please scratch the type comments, we don't need the type at all, as seen in the 2/2. Sorry about that. _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
