Hi This patch is very important due to [0]. Some cases generate loops in routers and high CPU load. Could someone review, please?
[0] https://www.mail-archive.com/ovs-discuss@openvswitch.org/msg10304.html Lucas Dias Em sex., 4 de abr. de 2025 às 10:37, Lucas Vargas Dias < lucas.vd...@luizalabs.com> escreveu: > Check if lsp exists in TS, if router-port of lsp exist > and lrp has the same network address of adversing. > If some of conditions is false, remove the route of routes > advertising. > Also, check if lrp that's learning a new route has address in the > same subnet of neighbor. > These verifications avoid loop that generates a high CPU load viewed in > ovsdb-server. > > Reported-at: > https://www.mail-archive.com/ovs-discuss@openvswitch.org/msg10304.html > Signed-off-by: Lucas Vargas Dias <lucas.vd...@luizalabs.com> > --- > ic/ovn-ic.c | 114 ++++++++++++++++++++++++- > tests/ovn-ic.at | 215 ++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 326 insertions(+), 3 deletions(-) > > diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c > index c8796680b..2285fabf2 100644 > --- a/ic/ovn-ic.c > +++ b/ic/ovn-ic.c > @@ -1315,11 +1315,52 @@ route_has_local_gw(const struct > nbrec_logical_router *lr, > return false; > } > > +static bool > +lrp_has_neighbor_in_ts(const struct nbrec_logical_router_port *lrp, > + struct in6_addr *nexthop) > +{ > + if (!lrp || !nexthop) { > + return false; > + } > + > + struct lport_addresses lrp_networks; > + if (!extract_lrp_networks(lrp, &lrp_networks)) { > + destroy_lport_addresses(&lrp_networks); > + return false; > + } > + > + if (IN6_IS_ADDR_V4MAPPED(nexthop)) { > + ovs_be32 neigh_prefix_v4 = in6_addr_get_mapped_ipv4(nexthop); > + for (size_t i = 0; i < lrp_networks.n_ipv4_addrs; i++) { > + struct ipv4_netaddr address = lrp_networks.ipv4_addrs[i]; > + if (address.network == (neigh_prefix_v4 & address.mask)) { > + destroy_lport_addresses(&lrp_networks); > + return true; > + } > + } > + } else { > + for (size_t i = 0; i < lrp_networks.n_ipv6_addrs; i++) { > + struct ipv6_netaddr address = lrp_networks.ipv6_addrs[i]; > + struct in6_addr neigh_prefix = ipv6_addr_bitand(nexthop, > + > &address.mask); > + if (ipv6_addr_equals(&address.network, &neigh_prefix)) { > + destroy_lport_addresses(&lrp_networks); > + return true; > + } > + } > + } > + > + destroy_lport_addresses(&lrp_networks); > + return false; > +} > + > static bool > route_need_learn(const struct nbrec_logical_router *lr, > const struct icsbrec_route *isb_route, > struct in6_addr *prefix, unsigned int plen, > - const struct smap *nb_options) > + const struct smap *nb_options, > + const struct nbrec_logical_router_port *ts_lrp, > + struct in6_addr *nexthop) > { > if (!smap_get_bool(nb_options, "ic-route-learn", false)) { > return false; > @@ -1344,6 +1385,10 @@ route_need_learn(const struct nbrec_logical_router > *lr, > return false; > } > > + if (!lrp_has_neighbor_in_ts(ts_lrp, nexthop)) { > + return false; > + } > + > return true; > } > > @@ -1374,6 +1419,67 @@ get_lrp_by_lrp_name(struct ic_context *ctx, const > char *lrp_name) > return lrp; > } > > +static const struct nbrec_logical_router_port * > +find_lrp_of_nexthop(struct ic_context *ctx, > + const struct icsbrec_route *isb_route) > +{ > + const struct nbrec_logical_router_port *lrp; > + const struct nbrec_logical_switch *ls; > + ls = find_ts_in_nb(ctx, isb_route->transit_switch); > + if (!ls) { > + return NULL; > + } > + > + struct in6_addr nexthop; > + if (!ip46_parse(isb_route->nexthop, &nexthop)) { > + return NULL; > + } > + > + for (size_t i = 0; i < ls->n_ports; i++) { > + char *lsp_name = ls->ports[i]->name; > + const char *lrp_name = get_lrp_name_by_ts_port_name(ctx, > + lsp_name); > + if (!lrp_name) { > + continue; > + } > + > + lrp = get_lrp_by_lrp_name(ctx, lrp_name); > + if (!lrp) { > + continue; > + } > + > + struct lport_addresses lrp_networks; > + if (!extract_lrp_networks(lrp, &lrp_networks)) { > + destroy_lport_addresses(&lrp_networks); > + continue; > + } > + > + if (IN6_IS_ADDR_V4MAPPED(&nexthop)) { > + ovs_be32 nexthop_v4 = in6_addr_get_mapped_ipv4(&nexthop); > + for (size_t i_v4 = 0; i_v4 < lrp_networks.n_ipv4_addrs; > i_v4++) { > + struct ipv4_netaddr address = > lrp_networks.ipv4_addrs[i_v4]; > + if (address.addr == nexthop_v4) { > + destroy_lport_addresses(&lrp_networks); > + return lrp; > + } > + } > + } else { > + for (size_t i_v6 = 0; i_v6 < lrp_networks.n_ipv6_addrs; > i_v6++) { > + struct ipv6_netaddr address = > lrp_networks.ipv6_addrs[i_v6]; > + struct in6_addr nexthop_v6 = ipv6_addr_bitand(&nexthop, > + > &address.mask); > + if (ipv6_addr_equals(&address.network, &nexthop_v6)) { > + destroy_lport_addresses(&lrp_networks); > + return lrp; > + } > + } > + } > + destroy_lport_addresses(&lrp_networks); > + } > + > + return NULL; > +} > + > static bool > lrp_is_ts_port(struct ic_context *ctx, struct ic_router_info *ic_lr, > const char *lrp_name) > @@ -1467,7 +1573,7 @@ sync_learned_routes(struct ic_context *ctx, > continue; > } > if (!route_need_learn(ic_lr->lr, isb_route, &prefix, plen, > - &nb_global->options)) { > + &nb_global->options, lrp, &nexthop)) { > continue; > } > > @@ -1778,7 +1884,7 @@ delete_orphan_ic_routes(struct ic_context *ctx, > ctx->icnbrec_transit_switch_by_name, t_sw_key); > icnbrec_transit_switch_index_destroy_row(t_sw_key); > > - if (!t_sw) { > + if (!t_sw || !find_lrp_of_nexthop(ctx, isb_route)) { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > VLOG_INFO_RL(&rl, "Deleting orphan ICDB:Route: %s->%s (%s, > rtb:%s," > " transit switch: %s)", isb_route->ip_prefix, > @@ -2215,6 +2321,8 @@ main(int argc, char *argv[]) > &nbrec_logical_router_col_external_ids); > > ovsdb_idl_add_table(ovnnb_idl_loop.idl, > &nbrec_table_logical_router_port); > + ovsdb_idl_add_column(ovnnb_idl_loop.idl, > + &nbrec_logical_router_port_col_mac); > ovsdb_idl_add_column(ovnnb_idl_loop.idl, > &nbrec_logical_router_port_col_name); > ovsdb_idl_add_column(ovnnb_idl_loop.idl, > diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at > index c8276189c..1a340b4ec 100644 > --- a/tests/ovn-ic.at > +++ b/tests/ovn-ic.at > @@ -3002,3 +3002,218 @@ OVN_CHECK_PACKETS([hv3/vif5-tx.pcap], > [expected-vif5]) > OVN_CLEANUP_IC([az1], [az2], [az3]) > AT_CLEANUP > ]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([ovn-ic -- Delete route lsp orphan]) > + > +ovn_init_ic_db > + > +for i in 1 2; do > + ovn_start az$i > + ovn_as az$i > + > + # Enable route learning at AZ level > + check ovn-nbctl set nb_global . options:ic-route-learn=true > + # Enable route advertising at AZ level > + check ovn-nbctl set nb_global . options:ic-route-adv=true > +done > + > +# Create new transit switches and LRs. Test topology is next: > +# > +# / transit switch (ts11) \ > +# logical router (lr11) - - logical router (lr12) > +# \ transit switch (ts12) / > +# > + > +# Create lr11, lr12, ts11, ts12 and connect them > +for i in 1 2; do > + ovn_as az$i > + > + lr=lr1$i > + check ovn-nbctl lr-add $lr > + > + for j in 1 2; do > + ts=ts1$j > + check ovn-ic-nbctl --wait=sb --may-exist ts-add $ts > + > + lrp=lrp-$lr-$ts > + lsp=lsp-$ts-$lr > + # Create LRP and connect to TS > + check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a$j:0$i > 169.254.10$j.$i/24 > + check ovn-nbctl lsp-add $ts $lsp \ > + -- lsp-set-addresses $lsp router \ > + -- lsp-set-type $lsp router \ > + -- lsp-set-options $lsp router-port=$lrp > + done > +done > + > +# Create directly-connected route in lr11 > +check ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12 aa:aa:aa:aa:bb:01 " > 192.168.0.1/24" > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep > 192.168 | > + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl > +192.168.0.0/24 169.254.101.2 > +192.168.0.0/24 169.254.102.2 > +]) > + > +check ovn_as az2 ovn-nbctl lrp-del lrp-lr12-ts12 > + > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep > 192.168 | > + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl > +192.168.0.0/24 169.254.101.2 > +]) > + > + > +OVN_CLEANUP_IC([az1], [az2]) > + > +AT_CLEANUP > +]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([ovn-ic -- Delete route lrp orphan]) > + > +ovn_init_ic_db > + > +for i in 1 2; do > + ovn_start az$i > + ovn_as az$i > + > + # Enable route learning at AZ level > + check ovn-nbctl set nb_global . options:ic-route-learn=true > + # Enable route advertising at AZ level > + check ovn-nbctl set nb_global . options:ic-route-adv=true > +done > + > +# Create new transit switches and LRs. Test topology is next: > +# > +# / transit switch (ts11) \ > +# logical router (lr11) - - logical router (lr12) > +# \ transit switch (ts12) / > +# > + > +# Create lr11, lr12, ts11, ts12 and connect them > +for i in 1 2; do > + ovn_as az$i > + > + lr=lr1$i > + check ovn-nbctl lr-add $lr > + > + for j in 1 2; do > + ts=ts1$j > + check ovn-ic-nbctl --wait=sb --may-exist ts-add $ts > + > + lrp=lrp-$lr-$ts > + lsp=lsp-$ts-$lr > + # Create LRP and connect to TS > + check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a$j:0$i > 169.254.10$j.$i/24 > + check ovn-nbctl lsp-add $ts $lsp \ > + -- lsp-set-addresses $lsp router \ > + -- lsp-set-type $lsp router \ > + -- lsp-set-options $lsp router-port=$lrp > + done > +done > + > +# Create directly-connected route in lr11 > +check ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12 aa:aa:aa:aa:bb:01 " > 192.168.0.1/24" > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep > 192.168 | > + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl > +192.168.0.0/24 169.254.101.2 > +192.168.0.0/24 169.254.102.2 > +]) > + > +check ovn_as az2 ovn-nbctl lsp-del lsp-ts12-lr12 > + > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep > 192.168 | > + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl > +192.168.0.0/24 169.254.101.2 > +]) > + > + > +OVN_CLEANUP_IC([az1], [az2]) > + > +AT_CLEANUP > +]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([ovn-ic -- Check loop with lsp orphan in same subnet of new lsp > in other TS]) > + > +ovn_init_ic_db > + > +for i in 1 2; do > + ovn_start az$i > + ovn_as az$i > + > + # Enable route learning at AZ level > + check ovn-nbctl set nb_global . options:ic-route-learn=true > + # Enable route advertising at AZ level > + check ovn-nbctl set nb_global . options:ic-route-adv=true > +done > + > +# Create new transit switches and LRs. Test topology is next: > +# > +# / transit switch (ts11) \ > +# logical router (lr11) - - logical router (lr12) > +# \ transit switch (ts12) / > +# > + > +# Create lr11, lr12 and ts11 and connect them > +for i in 1 2; do > + ovn_as az$i > + > + lr=lr1$i > + check ovn-nbctl lr-add $lr > + > + for j in 1; do > + ts=ts1$j > + check ovn-ic-nbctl --wait=sb --may-exist ts-add $ts > + > + lrp=lrp-$lr-$ts > + lsp=lsp-$ts-$lr > + # Create LRP and connect to TS > + check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a$j:0$i > 169.254.10$j.$i/24 > + check ovn-nbctl lsp-add $ts $lsp \ > + -- lsp-set-addresses $lsp router \ > + -- lsp-set-type $lsp router \ > + -- lsp-set-options $lsp router-port=$lrp > + done > +done > + > +# Create directly-connected route in lr11 > +check ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12 aa:aa:aa:aa:bb:01 " > 192.168.0.1/24" > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep > 192.168 | > + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl > +192.168.0.0/24 169.254.101.2 > +]) > + > +# Delete LRP connection from lr11 to ts11, keep lsp orphan > +check ovn_as az1 ovn-nbctl lrp-del lrp-lr11-ts11 > + > +# Create ts12, and connect lr11 and lr21 to it in the same subnet of ts11 > where > +# exist one lsp orphan > +for i in 1 2; do > + ovn_as az$i > + ts=ts12 > + > + lr=lr1$i > + for j in 1; do > + check ovn-ic-nbctl --wait=sb --may-exist ts-add $ts > + > + lrp=lrp-$lr-$ts > + lsp=lsp-$ts-$lr > + # Create LRP and connect to TS > + check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a$j:0$i > 169.254.10$j.$i$i/24 > + check ovn-nbctl lsp-add $ts $lsp \ > + -- lsp-set-addresses $lsp router \ > + -- lsp-set-type $lsp router \ > + -- lsp-set-options $lsp router-port=$lrp > + done > +done > + > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep > 192.168 | > + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl > +192.168.0.0/24 169.254.101.22 > +]) > + > +OVN_CLEANUP_IC([az1], [az2]) > + > +AT_CLEANUP > +]) > -- > 2.34.1 > > -- _‘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 d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev