Hi Jacob, Mairtin, Thanks for the patch and review!
On 6/5/26 2:36 PM, Mairtin O'Loingsigh wrote: > On Fri, Jun 05, 2026 at 01:21:15PM +0100, Mairtin O'Loingsigh via dev wrote: >> On Thu, Jun 04, 2026 at 03:33:17PM -0400, Jacob Tanenbaum wrote: >>> Users should be able to configure two logical routers that >>> simultaneously interact with the same host routing table (vrf). >>> >>> This is accomplished by first processing all the datapaths before >>> syncing the vrf tables. Now re_nl_sync_routes() is only called once per >>> vrf table. >>> >>> Reported-at: https://redhat.atlassian.net/browse/FDP-3472 >>> Reported-by: Dumitru Ceara <[email protected]> >>> Signed-off-by: Jacob Tanenbaum <[email protected]> >>> >>> diff --git a/NEWS b/NEWS >>> index 9839d19b9..0816cf748 100644 >>> --- a/NEWS >>> +++ b/NEWS >>> @@ -7,6 +7,7 @@ Post v26.03.0 >>> "lb-add", "meter-add", "lr-policy-add", and "lr-policy-del", and >>> fixed the "nfg-list" signature. >>> - Dynamic Routing: >>> + * Allow multiple routers to read the same VRF table. >>> * Add support for hub-and-spoke propagation via the "hub-spoke" option >>> in dynamic-routing-redistribute settings. >>> * Add ECMP/multi-homing support for EVPN FDB entries. FDB entries >>> diff --git a/controller/route-exchange.c b/controller/route-exchange.c >>> index 08e44e4f6..6bc08c1a6 100644 >>> --- a/controller/route-exchange.c >>> +++ b/controller/route-exchange.c >>> @@ -243,11 +243,26 @@ static int route_exchange_nl_status; >>> } \ >>> } while (0) >>> >>> +struct advertised_routes_for_table_id_entry { Nit: this is a bit too long, I'd just call it 'struct advertised_routes_entry'. >>> + struct hmap_node node; >>> + >>> + struct hmap routes; Instead of copying routes into this one, given that we only support a single router advertising into a given VRF table, we could just turn this into a 'const struct hmap *routes' pointing to that router's advertised routes table. >>> + uint32_t table_id; >>> + struct hmap datapaths; I'd move 'datapaths' before 'routes'. >>> + bool can_sync; >>> +}; >>> + >>> +struct datapath_entry { >>> + struct hmap_node node; >>> + >>> + const struct sbrec_datapath_binding *db; >>> +}; We don't really need a new data structure, we could just use a 'struct hmapx' in the advertised_routes_ structure above. That would simplify a bit the code. >>> + >>> void >>> route_exchange_run(const struct route_exchange_ctx_in *r_ctx_in, >>> struct route_exchange_ctx_out *r_ctx_out) >>> { >>> - struct hmap table_ids = HMAP_INITIALIZER(&table_ids); >>> + struct hmap advertised_routes = HMAP_INITIALIZER(&advertised_routes); >>> struct sset old_maintained_vrfs = >>> SSET_INITIALIZER(&old_maintained_vrfs); >>> sset_swap(&_maintained_vrfs, &old_maintained_vrfs); >>> struct hmap old_maintained_route_table = >>> @@ -259,13 +274,10 @@ route_exchange_run(const struct route_exchange_ctx_in >>> *r_ctx_in, >>> const struct advertise_datapath_entry *ad; >>> HMAP_FOR_EACH (ad, node, r_ctx_in->announce_routes) { >>> uint32_t table_id = route_get_table_id(ad->db); >>> - >>> - bool valid = TABLE_ID_VALID(table_id); >>> - if (!valid || !ovn_add_tnlid(&table_ids, table_id)) { >>> + if (!TABLE_ID_VALID(table_id)) { >>> VLOG_WARN_RL(&rl, "Unable to sync routes for datapath >>> "UUID_FMT": " >>> - "%s table id: %"PRIu32, >>> - UUID_ARGS(&ad->db->header_.uuid), >>> - !valid ? "invalid" : "duplicate", table_id); >>> + "invalid table id: %"PRIu32, >>> + UUID_ARGS(&ad->db->header_.uuid), table_id); >>> continue; >>> } >>> >>> @@ -290,24 +302,107 @@ route_exchange_run(const struct >>> route_exchange_ctx_in *r_ctx_in, >>> sset_find_and_delete(&old_maintained_vrfs, ad->vrf_name); >>> } >>> >>> - maintained_route_table_add(table_id); >>> - >>> - struct vector received_routes = >>> - VECTOR_EMPTY_INITIALIZER(struct re_nl_received_route_node); >>> - >>> - error = re_nl_sync_routes(table_id, &ad->routes, >>> - &received_routes); >>> - SET_ROUTE_EXCHANGE_NL_STATUS(error); >>> - >>> - sb_sync_learned_routes(&received_routes, ad->db, >>> - &ad->bound_ports, r_ctx_in->ovnsb_idl_txn, >>> - r_ctx_in->sbrec_port_binding_by_name, >>> - r_ctx_in->sbrec_learned_route_by_datapath, >>> - &r_ctx_out->sb_changes_pending); >>> - >>> - vector_push(r_ctx_out->route_table_watches, &table_id); >>> + struct advertised_routes_for_table_id_entry *entry; I'd initialize 'entry' to NULL here. >>> + uint32_t hash = maintained_route_table_hash(table_id); >>> + HMAP_FOR_EACH_WITH_HASH (entry, node, hash, &advertised_routes) { >>> + if (entry->table_id == table_id) { >>> + if (!hmap_is_empty(&ad->routes) && >>> + !hmap_is_empty(&entry->routes)) { >>> + VLOG_WARN_RL(&rl, "Multiple datapaths are distributing >>> " >>> + "routes on routing table %"PRIu32"", >>> + table_id); >>> + entry->can_sync = false; >>> + } >>> + break; >>> + } >>> + } Nit: empty line for readability. >>> + if (entry == NULL) { >>> + entry = xmalloc(sizeof *entry); >>> + *entry = (struct advertised_routes_for_table_id_entry) { >>> + .table_id = table_id, >>> + .routes = HMAP_INITIALIZER(&entry->routes), >>> + .datapaths = HMAP_INITIALIZER(&entry->datapaths), >>> + .can_sync = true, >>> + }; >>> + hmap_insert(&advertised_routes, &entry->node, hash); >>> + } Nit: empty line for readability. >>> + if (!entry->can_sync) { >>> + continue; >>> + } Nit: empty line for readability. >>> + struct datapath_entry *dp_entry = xmalloc(sizeof *dp_entry); >>> + *dp_entry = (struct datapath_entry) { >>> + .db = ad->db, >>> + }; >>> + >>> + hmap_insert(&entry->datapaths, >>> + &dp_entry->node, >>> + uuid_hash(&dp_entry->db->header_.uuid)); >>> + struct advertise_route_entry *are; >>> + HMAP_FOR_EACH (are, node, &ad->routes) { >>> + /* Copy the advertised routes into the >>> + * advertised_routes_for_table_id to keep track of >>> + * advertised routes that we see */ >>> + struct advertise_route_entry *copy = xmalloc(sizeof *copy); >>> + *copy = (struct advertise_route_entry) { >>> + .addr = are->addr, >>> + .plen = are->plen, >>> + .priority = are->priority, >>> + .nexthop = are->nexthop, >>> + }; >>> + hmap_insert(&entry->routes, >>> + ©->node, >>> + hmap_node_hash(&are->node)); >>> + } This whole block can be removed if we change to the single 'const struct hmap *' pointer as mentioned above. >>> + } >>> >>> - vector_destroy(&received_routes); >>> + struct advertised_routes_for_table_id_entry *arte; >>> + HMAP_FOR_EACH_POP (arte, node, &advertised_routes) { >>> + maintained_route_table_add(arte->table_id); >>> + if (arte->can_sync) { >>> + struct vector received_routes = >>> + VECTOR_EMPTY_INITIALIZER(struct re_nl_received_route_node); >>> + error = re_nl_sync_routes(arte->table_id, >>> + &arte->routes, >>> + &received_routes); >>> + SET_ROUTE_EXCHANGE_NL_STATUS(error); Nit: empty line for readability. >>> + struct ovsdb_idl_index *sbrec_learned_route_by_datapath = >>> + r_ctx_in->sbrec_learned_route_by_datapath; >>> + struct datapath_entry *dp; >>> + HMAP_FOR_EACH_POP (dp, node, &arte->datapaths) { >>> + struct advertise_datapath_entry *adpe = >>> + advertise_datapath_find(r_ctx_in->announce_routes, >>> + dp->db); >>> + if (!adpe) { >>> + VLOG_WARN_RL(&rl, "Cannot sync datapath binding >>> "UUID_FMT", bound " >>> + "ports not found", >>> + UUID_ARGS(&dp->db->header_.uuid)); >> Nit: I would move "Cannot .." to new line and fix alighment of "ports.. >> and UUID. +1 >>> + free(dp); >>> + continue; >>> + } >>> + sb_sync_learned_routes(&received_routes, dp->db, >>> + &adpe->bound_ports, >>> + r_ctx_in->ovnsb_idl_txn, >>> + >>> r_ctx_in->sbrec_port_binding_by_name, >>> + sbrec_learned_route_by_datapath, >>> + &r_ctx_out->sb_changes_pending); >>> + >>> + free(dp); >>> + } >>> + vector_push(r_ctx_out->route_table_watches, &arte->table_id); >>> + vector_destroy(&received_routes); >>> + } else { >>> + struct datapath_entry *dp; >>> + HMAP_FOR_EACH_POP (dp, node, &arte->datapaths) { >>> + free(dp); >>> + } >>> + } Nit: empty line for readability. >>> + hmap_destroy(&arte->datapaths); >>> + struct advertise_route_entry *ade; >>> + HMAP_FOR_EACH_POP (ade, node, &arte->routes) { >>> + free(ade); >>> + } >>> + hmap_destroy(&arte->routes); >>> + free(arte); >>> } >>> >>> /* Remove routes in tables previously maintained by us. */ >>> @@ -339,7 +434,7 @@ route_exchange_run(const struct route_exchange_ctx_in >>> *r_ctx_in, >>> sset_delete(&old_maintained_vrfs, SSET_NODE_FROM_NAME(vrf_name)); >>> } >>> sset_destroy(&old_maintained_vrfs); >>> - ovn_destroy_tnlids(&table_ids); >>> + hmap_destroy(&advertised_routes); >>> } >>> >>> void >>> diff --git a/controller/route.c b/controller/route.c >>> index 49344231f..13e6d3010 100644 >>> --- a/controller/route.c >>> +++ b/controller/route.c >>> @@ -115,6 +115,19 @@ route_exchange_find_port(struct ovsdb_idl_index >>> *sbrec_port_binding_by_name, >>> return NULL; >>> } >>> >>> +struct advertise_datapath_entry * >>> +advertise_datapath_find(const struct hmap *datapaths, >>> + const struct sbrec_datapath_binding *db) >>> +{ >>> + struct advertise_datapath_entry *ade; >>> + HMAP_FOR_EACH_WITH_HASH (ade, node, db->tunnel_key, datapaths) { >>> + if (ade->db == db) { >>> + return ade; >>> + } >>> + } >>> + return NULL; >>> +} >>> + >>> static void >>> build_port_mapping(struct smap *mapping, const char *port_mapping) >>> { >>> @@ -172,19 +185,6 @@ advertise_datapath_cleanup(struct >>> advertise_datapath_entry *ad) >>> free(ad); >>> } >>> >>> -static struct advertise_datapath_entry* >>> -advertise_datapath_find(const struct hmap *datapaths, >>> - const struct sbrec_datapath_binding *db) >>> -{ >>> - struct advertise_datapath_entry *ade; >>> - HMAP_FOR_EACH_WITH_HASH (ade, node, db->tunnel_key, datapaths) { >>> - if (ade->db == db) { >>> - return ade; >>> - } >>> - } >>> - return NULL; >>> -} >>> - >>> static struct advertise_datapath_entry * >>> advertised_datapath_alloc(const struct sbrec_datapath_binding *datapath) >>> { >>> diff --git a/controller/route.h b/controller/route.h >>> index 108e34200..43d11730b 100644 >>> --- a/controller/route.h >>> +++ b/controller/route.h >>> @@ -105,5 +105,8 @@ struct advertise_route_entry * >>> advertise_route_find(unsigned int priority, const struct in6_addr *prefix, >>> unsigned int plen, const struct in6_addr *nexthop, >>> const struct hmap *advertised_routes); >>> +struct advertise_datapath_entry * >>> +advertise_datapath_find(const struct hmap *datapaths, >>> + const struct sbrec_datapath_binding *db); Nit: 'db' can be omitted. >>> >>> #endif /* ROUTE_H */ >>> diff --git a/tests/system-ovn.at b/tests/system-ovn.at >>> index 49aada46d..9594d594d 100644 >>> --- a/tests/system-ovn.at >>> +++ b/tests/system-ovn.at >>> @@ -20486,6 +20486,8 @@ check ovn-nbctl --wait=hv set Logical_Router lr-frr >>> options:dynamic-routing-no-l >>> # Verify routes do not appear in SB database. >>> wait_row_count Learned_Route 0 >>> >>> +check ovn-nbctl --wait=hv remove Logical_Router lr-tenant options >>> dynamic-routing dynamic-routing-vrf-id >>> + >>> check ovn-nbctl --wait=hv set Logical_Router lr-frr >>> options:dynamic-routing-no-learning=false >>> >>> # Verify learned route appears in SB database >>> @@ -20583,6 +20585,37 @@ ip_prefix : "10.10.3.1" >>> ip_prefix : "10.10.4.1" >>> ]) >>> >>> +# Verify that we can have one router read and another write from the same >>> vrf table Nit: comments should be sentences and end with period. >>> +# >>> +# The router that advertises needs to have the gateway chassis set so >>> remove the >>> +# redistribute routes from lr-frr >>> + >>> +check ovn-nbctl remove Logical_Router lr-frr options >>> dynamic-routing-redistribute >>> +check ovn-nbctl --wait=hv set Logical_Router lr-frr \ >>> + options:dynamic-routing-vrf-id=$vni >>> + >>> +check ovn-nbctl --wait=hv set Logical_Router lr-tenant \ >>> + options:dynamic-routing-vrf-id=$vni \ >>> + options:dynamic-routing=true \ >>> + options:dynamic-routing-redistribute=static \ >>> + options:dynamic-routing-no-learning=true >>> + >>> + >>> +# Verify that lr-frr has Learned_Routes but lr-tenant does not >>> +wait_row_count Learned_Route 2 >>> +wait_row_count Advertised_Route 1 We can strenghten this check by explicitly checking each datapath: dp_frr=$(fetch_column Datapath_Binding _uuid external_ids:name=lr-frr) dp_tenant=$(fetch_column Datapath_Binding _uuid external_ids:name=lr-tenant) wait_row_count Learned_Route 2 datapath=$dp_frr wait_row_count Learned_Route 0 datapath=$dp_tenant wait_row_count Advertised_Route 0 datapath=$dp_frr wait_row_count Advertised_Route 1 datapath=$dp_tenant >>> +OVN_ROUTE_EQUAL([vrf-$vni], [dnl >>> +blackhole 10.10.1.1 proto ovn metric 1000 >>> +10.10.3.1 via 20.0.0.25 dev local-bgp-port proto zebra >>> +10.10.4.1 via 20.0.0.25 dev local-bgp-port proto zebra >>> +20.0.0.0/8 dev local-bgp-port proto kernel scope link src 20.0.0.4]) >>> +OVS_WAIT_FOR_OUTPUT([ip route show table $vni type blackhole | wc -l], >>> [0], [dnl >>> +1 >>> +]) >>> + >>> +check ovn-nbctl remove Logical_Router lr-tenant options >>> dynamic-routing-vrf-id dynamic-routing I'd remove all dynamic-routing-* options we have added here. >>> + >>> + >>> # Remove lrp-local-bgp-port port. >>> AS_BOX([$(date +%H:%M:%S.%03N) Remove lrp]) >>> check ovn-nbctl --wait=hv lrp-del lrp-local-bgp-port >>> -- >>> 2.54.0 >>> >> LGTM >> One small nit that can be fixed on merge. >> >> Acked-by: Mairtin O'Loingsigh [email protected] >> >> _______________________________________________ >> dev mailing list >> [email protected] >> https://mail.openvswitch.org/mailman/listinfo/ovs-dev >> > > Adding ack again as previous ack format was not correct. > Acked-by: Mairtin O'Loingsigh <[email protected]> > My additional comments above were minor so I went ahead and fixed them up in the patch and applied it to main and 26.03. Full incremental diff below. Thanks, Dumitru --- diff --git a/controller/route-exchange.c b/controller/route-exchange.c index 6bc08c1a63..b86eb43bf2 100644 --- a/controller/route-exchange.c +++ b/controller/route-exchange.c @@ -21,6 +21,7 @@ #include <net/if.h> #include <stdbool.h> +#include "hmapx.h" #include "openvswitch/poll-loop.h" #include "openvswitch/vlog.h" #include "openvswitch/list.h" @@ -243,21 +244,15 @@ static int route_exchange_nl_status; } \ } while (0) -struct advertised_routes_for_table_id_entry { +struct advertised_routes_entry { struct hmap_node node; - struct hmap routes; + struct hmapx datapaths; + const struct hmap *routes; uint32_t table_id; - struct hmap datapaths; bool can_sync; }; -struct datapath_entry { - struct hmap_node node; - - const struct sbrec_datapath_binding *db; -}; - void route_exchange_run(const struct route_exchange_ctx_in *r_ctx_in, struct route_exchange_ctx_out *r_ctx_out) @@ -302,106 +297,79 @@ route_exchange_run(const struct route_exchange_ctx_in *r_ctx_in, sset_find_and_delete(&old_maintained_vrfs, ad->vrf_name); } - struct advertised_routes_for_table_id_entry *entry; + struct advertised_routes_entry *entry = NULL; uint32_t hash = maintained_route_table_hash(table_id); HMAP_FOR_EACH_WITH_HASH (entry, node, hash, &advertised_routes) { if (entry->table_id == table_id) { - if (!hmap_is_empty(&ad->routes) && - !hmap_is_empty(&entry->routes)) { - VLOG_WARN_RL(&rl, "Multiple datapaths are distributing " - "routes on routing table %"PRIu32"", - table_id); - entry->can_sync = false; + if (!hmap_is_empty(&ad->routes)) { + if (entry->routes && !hmap_is_empty(entry->routes)) { + VLOG_WARN_RL(&rl, + "Multiple datapaths are distributing " + "routes on routing table %"PRIu32, + table_id); + entry->can_sync = false; + } else { + entry->routes = &ad->routes; + } } break; } } + if (entry == NULL) { entry = xmalloc(sizeof *entry); - *entry = (struct advertised_routes_for_table_id_entry) { + *entry = (struct advertised_routes_entry) { + .datapaths = HMAPX_INITIALIZER(&entry->datapaths), + .routes = &ad->routes, .table_id = table_id, - .routes = HMAP_INITIALIZER(&entry->routes), - .datapaths = HMAP_INITIALIZER(&entry->datapaths), .can_sync = true, }; hmap_insert(&advertised_routes, &entry->node, hash); } + if (!entry->can_sync) { continue; } - struct datapath_entry *dp_entry = xmalloc(sizeof *dp_entry); - *dp_entry = (struct datapath_entry) { - .db = ad->db, - }; - - hmap_insert(&entry->datapaths, - &dp_entry->node, - uuid_hash(&dp_entry->db->header_.uuid)); - struct advertise_route_entry *are; - HMAP_FOR_EACH (are, node, &ad->routes) { - /* Copy the advertised routes into the - * advertised_routes_for_table_id to keep track of - * advertised routes that we see */ - struct advertise_route_entry *copy = xmalloc(sizeof *copy); - *copy = (struct advertise_route_entry) { - .addr = are->addr, - .plen = are->plen, - .priority = are->priority, - .nexthop = are->nexthop, - }; - hmap_insert(&entry->routes, - ©->node, - hmap_node_hash(&are->node)); - } + + hmapx_add(&entry->datapaths, CONST_CAST(void *, ad->db)); } - struct advertised_routes_for_table_id_entry *arte; + struct advertised_routes_entry *arte; HMAP_FOR_EACH_POP (arte, node, &advertised_routes) { maintained_route_table_add(arte->table_id); if (arte->can_sync) { struct vector received_routes = VECTOR_EMPTY_INITIALIZER(struct re_nl_received_route_node); - error = re_nl_sync_routes(arte->table_id, - &arte->routes, + error = re_nl_sync_routes(arte->table_id, arte->routes, &received_routes); SET_ROUTE_EXCHANGE_NL_STATUS(error); + struct ovsdb_idl_index *sbrec_learned_route_by_datapath = r_ctx_in->sbrec_learned_route_by_datapath; - struct datapath_entry *dp; - HMAP_FOR_EACH_POP (dp, node, &arte->datapaths) { + struct hmapx_node *dp_node; + HMAPX_FOR_EACH (dp_node, &arte->datapaths) { + const struct sbrec_datapath_binding *db = dp_node->data; struct advertise_datapath_entry *adpe = advertise_datapath_find(r_ctx_in->announce_routes, - dp->db); + db); if (!adpe) { - VLOG_WARN_RL(&rl, "Cannot sync datapath binding "UUID_FMT", bound " - "ports not found", - UUID_ARGS(&dp->db->header_.uuid)); - free(dp); + VLOG_WARN_RL(&rl, "Cannot sync datapath binding " + UUID_FMT", bound ports not found", + UUID_ARGS(&db->header_.uuid)); continue; } - sb_sync_learned_routes(&received_routes, dp->db, + sb_sync_learned_routes(&received_routes, db, &adpe->bound_ports, r_ctx_in->ovnsb_idl_txn, r_ctx_in->sbrec_port_binding_by_name, sbrec_learned_route_by_datapath, &r_ctx_out->sb_changes_pending); - - free(dp); } vector_push(r_ctx_out->route_table_watches, &arte->table_id); vector_destroy(&received_routes); - } else { - struct datapath_entry *dp; - HMAP_FOR_EACH_POP (dp, node, &arte->datapaths) { - free(dp); - } - } - hmap_destroy(&arte->datapaths); - struct advertise_route_entry *ade; - HMAP_FOR_EACH_POP (ade, node, &arte->routes) { - free(ade); } - hmap_destroy(&arte->routes); + + hmapx_destroy(&arte->datapaths); free(arte); } diff --git a/controller/route.h b/controller/route.h index 43d11730be..f1d03a9e5a 100644 --- a/controller/route.h +++ b/controller/route.h @@ -107,6 +107,6 @@ advertise_route_find(unsigned int priority, const struct in6_addr *prefix, const struct hmap *advertised_routes); struct advertise_datapath_entry * advertise_datapath_find(const struct hmap *datapaths, - const struct sbrec_datapath_binding *db); + const struct sbrec_datapath_binding *); #endif /* ROUTE_H */ diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 6a929823e1..740e12e9e3 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -20506,12 +20506,14 @@ ip_prefix : "10.10.3.1" ip_prefix : "10.10.4.1" ]) -# Verify that we can have one router read and another write from the same vrf table +# Verify that we can have one router read and another write from the same +# vrf table. # # The router that advertises needs to have the gateway chassis set so remove the -# redistribute routes from lr-frr +# redistribute routes from lr-frr. -check ovn-nbctl remove Logical_Router lr-frr options dynamic-routing-redistribute +check ovn-nbctl remove Logical_Router lr-frr options \ + dynamic-routing-redistribute check ovn-nbctl --wait=hv set Logical_Router lr-frr \ options:dynamic-routing-vrf-id=$vni @@ -20522,9 +20524,13 @@ check ovn-nbctl --wait=hv set Logical_Router lr-tenant \ options:dynamic-routing-no-learning=true -# Verify that lr-frr has Learned_Routes but lr-tenant does not -wait_row_count Learned_Route 2 -wait_row_count Advertised_Route 1 +# Verify that lr-frr has Learned_Routes but lr-tenant does not. +dp_frr=$(fetch_column Datapath_Binding _uuid external_ids:name=lr-frr) +dp_tenant=$(fetch_column Datapath_Binding _uuid external_ids:name=lr-tenant) +wait_row_count Learned_Route 2 datapath=$dp_frr +wait_row_count Learned_Route 0 datapath=$dp_tenant +wait_row_count Advertised_Route 0 datapath=$dp_frr +wait_row_count Advertised_Route 1 datapath=$dp_tenant OVN_ROUTE_EQUAL([vrf-$vni], [dnl blackhole 10.10.1.1 proto ovn metric 1000 10.10.3.1 via 20.0.0.25 dev local-bgp-port proto zebra @@ -20534,8 +20540,10 @@ OVS_WAIT_FOR_OUTPUT([ip route show table $vni type blackhole | wc -l], [0], [dnl 1 ]) -check ovn-nbctl remove Logical_Router lr-tenant options dynamic-routing-vrf-id dynamic-routing - +check ovn-nbctl remove Logical_Router lr-tenant options \ + dynamic-routing-vrf-id dynamic-routing \ + dynamic-routing-redistribute \ + dynamic-routing-no-learning # Remove lrp-local-bgp-port port. AS_BOX([$(date +%H:%M:%S.%03N) Remove lrp]) --- _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
