If logical router has more than one LRP as gateway router port and dynamic routing configured, dynamic-routing-port-name could be used to specify the LRP that will be used to dynamic routing. However, if all LRPs learning routes, routes from LRP without dynamic-routing-port-name must be flushed. This happens when LRPs are scheduled in the same chassis.
Signed-off-by: Lucas Vargas Dias <[email protected]> --- controller/ovn-controller.c | 16 ++++ controller/route-exchange.c | 47 +++++++++++- controller/route-exchange.h | 1 + tests/ovn-inc-proc-graph-dump.at | 2 + tests/system-ovn.at | 125 +++++++++++++++++++++++++++++++ 5 files changed, 187 insertions(+), 4 deletions(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 2d9b3e033..1c7b3b256 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -5494,10 +5494,24 @@ en_route_exchange_run(struct engine_node *node, void *data) return EN_STALE; } + const struct ovsrec_open_vswitch_table *ovs_table = + EN_OVSDB_GET(engine_get_input("OVS_open_vswitch", node)); + const char *chassis_id = get_ovs_chassis_id(ovs_table); + ovs_assert(chassis_id); + + struct ovsdb_idl_index *sbrec_chassis_by_name = + engine_ovsdb_node_get_index( + engine_get_input("SB_chassis", node), + "name"); + const struct sbrec_chassis *chassis + = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id); + ovs_assert(chassis); + struct route_exchange_ctx_in r_ctx_in = { .ovnsb_idl_txn = engine_get_context()->ovnsb_idl_txn, .sbrec_learned_route_by_datapath = sbrec_learned_route_by_datapath, .sbrec_port_binding_by_name = sbrec_port_binding_by_name, + .chassis = chassis, .announce_routes = &route_data->announce_routes, }; struct route_exchange_ctx_out r_ctx_out = { @@ -6679,6 +6693,8 @@ inc_proc_ovn_controller_init( engine_add_input(&en_route, &en_sb_datapath_binding, route_sb_datapath_binding_handler); + engine_add_input(&en_route_exchange, &en_ovs_open_vswitch, NULL); + engine_add_input(&en_route_exchange, &en_sb_chassis, NULL); engine_add_input(&en_route_exchange, &en_route, NULL); engine_add_input(&en_route_exchange, &en_sb_learned_route, engine_noop_handler); diff --git a/controller/route-exchange.c b/controller/route-exchange.c index ae44ffe69..f8a36f55d 100644 --- a/controller/route-exchange.c +++ b/controller/route-exchange.c @@ -26,6 +26,7 @@ #include "openvswitch/list.h" #include "lib/ovn-sb-idl.h" +#include "lib/uuidset.h" #include "binding.h" #include "ha-chassis.h" @@ -86,7 +87,7 @@ maintained_route_table_add(uint32_t table_id) hmap_insert(&_maintained_route_tables, &mrt->node, hash); } -static void +static struct route_entry * route_add_entry(struct hmap *routes, const struct sbrec_learned_route *sb_route, bool stale) @@ -102,6 +103,7 @@ route_add_entry(struct hmap *routes, hash = hash_string(sb_route->ip_prefix, hash); hmap_insert(routes, &route_e->hmap_node, hash); + return route_e; } static struct route_entry * @@ -144,28 +146,64 @@ sb_sync_learned_routes(const struct vector *learned_routes, struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_port_binding_by_name, struct ovsdb_idl_index *sbrec_learned_route_by_datapath, - bool *sb_changes_pending) + bool *sb_changes_pending, + const struct sbrec_chassis *chassis) { struct hmap sync_routes = HMAP_INITIALIZER(&sync_routes); const struct sbrec_learned_route *sb_route; - struct route_entry *route_e; + struct route_entry *route_e = NULL; + struct uuidset uuid_set = UUIDSET_INITIALIZER(&uuid_set); struct sbrec_learned_route *filter = sbrec_learned_route_index_init_row(sbrec_learned_route_by_datapath); sbrec_learned_route_index_set_datapath(filter, datapath); SBREC_LEARNED_ROUTE_FOR_EACH_EQUAL (sb_route, filter, sbrec_learned_route_by_datapath) { + const struct sbrec_port_binding *cr_pb = + lport_get_cr_port(sbrec_port_binding_by_name, + sb_route->logical_port, NULL); + const char *dynamic_routing_port_name = + smap_get(&sb_route->logical_port->options, + "dynamic-routing-port-name"); + if (!dynamic_routing_port_name && cr_pb) { + dynamic_routing_port_name = + smap_get(&cr_pb->options, "dynamic-routing-port-name"); + } + + if (sb_route->logical_port->chassis == chassis || + (cr_pb && cr_pb->chassis == chassis)) { + route_e = route_add_entry(&sync_routes, sb_route, false); + if (dynamic_routing_port_name) { + uuidset_insert(&uuid_set, + &sb_route->logical_port->header_.uuid); + } + } + /* If the port is not local we don't care about it. * Some other ovn-controller will handle it. * We may not use smap_get since the value might be validly NULL. */ if (!smap_get_node(bound_ports, sb_route->logical_port->logical_port)) { + route_e = NULL; + continue; + } + if (route_e) { + route_e->stale = true; continue; } route_add_entry(&sync_routes, sb_route, true); } sbrec_learned_route_index_destroy_row(filter); + if (!uuidset_is_empty(&uuid_set)) { + HMAP_FOR_EACH_SAFE (route_e, hmap_node, &sync_routes) { + if (!uuidset_find(&uuid_set, + &route_e->sb_route->logical_port->header_.uuid)) { + route_e->stale = true; + } + } + } + uuidset_destroy(&uuid_set); struct re_nl_received_route_node *learned_route; VECTOR_FOR_EACH_PTR (learned_routes, learned_route) { char *ip_prefix = normalize_v46_prefix(&learned_route->prefix, @@ -304,7 +342,8 @@ route_exchange_run(const struct route_exchange_ctx_in *r_ctx_in, &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); + &r_ctx_out->sb_changes_pending, + r_ctx_in->chassis); route_table_add_watch_request(&r_ctx_out->route_table_watches, table_id); diff --git a/controller/route-exchange.h b/controller/route-exchange.h index e3791c331..53828a8b9 100644 --- a/controller/route-exchange.h +++ b/controller/route-exchange.h @@ -24,6 +24,7 @@ struct route_exchange_ctx_in { struct ovsdb_idl_txn *ovnsb_idl_txn; struct ovsdb_idl_index *sbrec_port_binding_by_name; struct ovsdb_idl_index *sbrec_learned_route_by_datapath; + const struct sbrec_chassis *chassis; /* Contains struct advertise_datapath_entry */ const struct hmap *announce_routes; diff --git a/tests/ovn-inc-proc-graph-dump.at b/tests/ovn-inc-proc-graph-dump.at index 3fe7b8fbd..0a514ffe5 100644 --- a/tests/ovn-inc-proc-graph-dump.at +++ b/tests/ovn-inc-proc-graph-dump.at @@ -460,6 +460,8 @@ digraph "Incremental-Processing-Engine" { route_table_notify [[style=filled, shape=box, fillcolor=white, label="route_table_notify"]]; route_exchange_status [[style=filled, shape=box, fillcolor=white, label="route_exchange_status"]]; route_exchange [[style=filled, shape=box, fillcolor=white, label="route_exchange"]]; + OVS_open_vswitch -> route_exchange [[label=""]]; + SB_chassis -> route_exchange [[label=""]]; route -> route_exchange [[label=""]]; SB_learned_route -> route_exchange [[label="engine_noop_handler"]]; SB_port_binding -> route_exchange [[label="engine_noop_handler"]]; diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 67f03e3be..b0a023791 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -20593,3 +20593,128 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d /connection dropped.*/d"]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([dynamic-routing - BGP learned routes with router filter name and multiple DGPs]) + +# This test validates that BGP learned routes work correctly: +# 1. Routes added to the VRF appear in Learned_Route table +# 2. Stopping ovn-controller remove learned routes +# +# Topology: +# +---------+ +# | public | +# +----+----+ +# | +# +----+---+ +# | lr-frr | (in VRF 10) +# +----+---+ +# | +# +------+-------+ +# |local-bgp-port| (in VRF 10) +# +--------------+ + +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) +ADD_BR([br-ex]) + +check ovs-ofctl add-flow br-ex action=normal + +# Set external-ids in br-int needed for ovn-controller +check ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Configure bridge mappings for localnet +check ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phys:br-ex + +id=10 + +# Start ovn-controller +start_daemon ovn-controller + +check ip link add vrf-$id type vrf table $id +on_exit "ip link del vrf-$id" +check ip link set vrf-$id up + +# Create public logical switch with localnet port +check ovn-nbctl ls-add public +check ovn-nbctl lsp-add-localnet-port public ln_port phys + +# Create lr-frr with dynamic routing in VRF $id +check ovn-nbctl lr-add lr-frr \ + -- set Logical_Router lr-frr \ + options:dynamic-routing=true \ + options:dynamic-routing-vrf-id=$id \ + options:dynamic-routing-redistribute=static + +check ovn-nbctl lrp-add lr-frr lrp-local-bgp-port 00:00:00:00:00:03 20.0.0.3/24 \ + -- set Logical_Router_Port lrp-local-bgp-port options:dynamic-routing-maintain-vrf=false \ + -- set Logical_Router_Port lrp-local-bgp-port options:routing-protocol-redirect=local-bgp-port + +check ovn-nbctl lrp-set-gateway-chassis lrp-local-bgp-port hv1 +check ovn-nbctl lsp-add-router-port public public-lr-frr lrp-local-bgp-port + +check ovn-nbctl lrp-add lr-frr lrp-dgp-dummy 00:00:00:00:00:04 20.0.1.3/24 +check ovn-nbctl lrp-set-gateway-chassis lrp-dgp-dummy hv1 +check ovn-nbctl ls-add ls-dummy +check ovn-nbctl lsp-add-router-port ls-dummy lsp-dummy lrp-dgp-dummy + + +# Create local-bgp-port in VRF 10 +check ovs-vsctl add-port br-int local-bgp-port \ + -- set Interface local-bgp-port type=internal \ + -- set Interface local-bgp-port external_ids:iface-id=local-bgp-port + +check ovn-nbctl lsp-add public local-bgp-port \ + -- lsp-set-addresses local-bgp-port unknown + +# Configure local-bgp-port interface and add to VRF +check ip link set local-bgp-port master vrf-$id +check ip link set local-bgp-port address 00:00:00:00:00:03 +check ip addr add dev local-bgp-port 20.0.0.3/24 +check ip link set local-bgp-port up + +# Wait for everything to be ready +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +# Check lrp-local-bgp-port has dynamic-routing option set. +check_row_count Port_Binding 1 logical_port=cr-lrp-local-bgp-port 'options:dynamic-routing=true' + +# Add static routes +check ovn-nbctl lr-route-add lr-frr 10.10.2.1 20.0.0.42 lrp-local-bgp-port + +# Verify advertised routes exist +AS_BOX([Advertised_Route]) +wait_row_count Advertised_Route 1 ip_prefix=10.10.2.1 + +# Add a route to the VRF (simulating BGP learning a route) +check ip route add 10.10.3.1 via 20.0.0.25 vrf vrf-$id proto zebra + +# Verify learned route appears in SB database +check_row_count Learned_Route 2 ip_prefix=10.10.3.1 + +check ovn-nbctl --wait=hv set Logical_Router_Port lrp-local-bgp-port options:dynamic-routing-port-name=bgpvrf1002 + +check_row_count Learned_Route 1 ip_prefix=10.10.3.1 + +# Stop ovn-controller +OVN_CLEANUP_CONTROLLER([hv1], [], [], [lr-frr]) +check ovn-nbctl --wait=sb sync + +# Verify routes are removed in SB database. +wait_row_count Learned_Route 0 + +OVN_CLEANUP_NORTHD + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d +/failed to query port patch-.*/d +/.*terminating with signal 15.*/d"]) +AT_CLEANUP +]) -- 2.43.0 -- _'Esta mensagem é direcionada apenas para os endereços constantes no cabeçalho inicial. Se você não está listado nos endereços constantes no cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas estão imediatamente anuladas e proibidas'._ * **'Apesar do Magazine Luiza tomar todas as precauções razoáveis para assegurar que nenhum vírus esteja presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.* _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
