On 1/26/26 10:39 AM, Martin Kalcok via dev wrote:
> There were concerns about the amount of lookups made to accommodate this
> feature. This commit attempts to reduce them by storing `svc_mon_lrp` in the
> `struct ovn_northd_lb_backend`.
> There is still one lookup in the `ovn_lb_svc_create` function that searches
> all LRPs of the associated LRs for the one that matches configured source IP.
> However, there are no more lookups when creating ARP responder flows and
> health check response flows.
> 
> This change is intentionally submitted as a separate commit, for ease of
> review/rejection. Should it be accepted, it can be squashed into the
> original commit and this commit message discarded.
> 
> Signed-off-by: Martin Kalcok <[email protected]>
> ---

Hi Martin,

Thanks for sending this as a separate incremental, it's useful!

I had some comments on the first patch.  When you post v4 please squash
this patch into the first one, I think it's a very good addition.

Please see some more comments below.

Regards,
Dumitru

>  northd/lb.c     |  1 +
>  northd/lb.h     |  4 ++++
>  northd/northd.c | 60 +++++++++++++++++++------------------------------
>  3 files changed, 28 insertions(+), 37 deletions(-)
> 
> diff --git a/northd/lb.c b/northd/lb.c
> index 0822bc2d7..26d5bc87a 100644
> --- a/northd/lb.c
> +++ b/northd/lb.c
> @@ -196,6 +196,7 @@ ovn_lb_vip_backends_health_check_init(const struct 
> ovn_northd_lb *lb,
>              backend_nb->svc_mon_src_ip = svc_mon_src_ip;
>              backend_nb->az_name = is_remote ? xstrdup(az_name) : NULL;
>              backend_nb->remote_backend = is_remote;
> +            backend_nb->svc_mon_lrp = NULL;
>          }
>          free(port_name);
>      }
> diff --git a/northd/lb.h b/northd/lb.h
> index 53dc4abf0..435d9942a 100644
> --- a/northd/lb.h
> +++ b/northd/lb.h
> @@ -97,6 +97,10 @@ struct ovn_northd_lb_backend {
>      char *svc_mon_src_ip;
>      /* Target Availability Zone name for service monitoring. */
>      char *az_name;
> +    /* LRP used as the source of health_check traffic. This may be NULL if
> +     * health_check uses "reserved" IP address that does not belong to any
> +     * LRP in the backend's datapath. */
> +    struct ovn_port *svc_mon_lrp;

const?

>  };
>  
>  struct ovn_northd_lb *ovn_northd_lb_create(const struct nbrec_load_balancer 
> *);
> diff --git a/northd/northd.c b/northd/northd.c
> index 1e4e24216..2cbd8f9f3 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -3262,9 +3262,9 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn,
>  
>              /* If the service monitor is backed by a real port, use its MAC
>               * address instead of the default service check MAC. */
> -            const char *source_mac = svc_monitor_mac;
>              const struct eth_addr *source_mac_ea = svc_monitor_mac_ea;
> -            if (op) {
> +            const char *source_mac = svc_monitor_mac;
> +            if (op && !backend_nb->remote_backend) {
>                  struct ovn_port *svc_mon_op;
>                  VECTOR_FOR_EACH (&op->od->router_ports, svc_mon_op) {
>                      if (!svc_mon_op->peer) {
> @@ -3277,6 +3277,9 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn,
>                                            backend_nb->svc_mon_src_ip)) {
>                          source_mac = svc_mon_op->peer->lrp_networks.ea_s;
>                          source_mac_ea = &svc_mon_op->peer->lrp_networks.ea;
> +                        /* Store LRP that's used as the source of service
> +                         * monitor traffic, to avoid later lookups. */
> +                        backend_nb->svc_mon_lrp = svc_mon_op->peer;

It's due to the way LBs are applied to multiple switches/routers in the
huge northd node but ideally this should be part of the svc_lb
initialization.  I know it's a bit over-kill but since we can't do that
let's add a simple setter function in northd/lb.[ch] to set the
backend_nb->svc_mon_lrp?

We could move this whole chunk above (starting with "/* If the service
monitor is backed by a real port, use its MAC") to the new function I think.

It's more work but we at least "pretend" we properly initialized the LB
somewhere else and that here we just process what's in the LB and its
backends.

>                          break;
>                      }
>                  }
> @@ -8542,7 +8545,7 @@ build_lb_health_check_response_lflows(
>          struct ovn_northd_lb_backend *backend_nb =
>              &lb_vip_nb->backends_nb[j++];
>  
> -        if (!backend_nb->health_check) {
> +        if (!backend_nb->health_check || !backend_nb->svc_mon_lrp) {
>              continue;
>          }
>  
> @@ -8555,24 +8558,21 @@ build_lb_health_check_response_lflows(
>          DYNAMIC_BITMAP_FOR_EACH_1 (index, &lb_dps->nb_lr_map) {
>              struct ovn_datapath *od = sparse_array_get(&lr_datapaths->dps,
>                                                          index);
> -            /* Only install the rule if the datapath has a port with
> -             * monitor source IP. */
> -            struct ovn_datapath *peer_switch_od = NULL;
> -            struct ovn_port *svc_mon_op;
> +            if (!od) {
> +                continue;
> +            }
>  
> -            HMAP_FOR_EACH (svc_mon_op, dp_node, &od->ports) {
> -                if (!svc_mon_op->peer) {
> -                    continue;
> -                }
> -                const char *lrp_ip = lrp_find_member_ip(
> -                    svc_mon_op,
> -                    backend_nb->svc_mon_src_ip);
> -                if (lrp_ip &&
> -                        !strcmp(lrp_ip, backend_nb->svc_mon_src_ip)) {
> -                    peer_switch_od = svc_mon_op->peer->od;
> -                    break;
> -                }
> +            /* Check if the "service monitor source" LRP belongs to this
> +             * router. */
> +            if (backend_nb->svc_mon_lrp->od != od) {
> +                continue;
>              }
> +
> +            /* Get the peer switch datapath where the backend is located. */
> +            struct ovn_datapath *peer_switch_od =
> +                backend_nb->svc_mon_lrp->peer
> +                ? backend_nb->svc_mon_lrp->peer->od
> +                : NULL;

Nit: this indentation seems a bit odd to me.  I think I'd just:

            /* Get the peer switch datapath where the... . */
            struct ovn_datapath *peer_switch_od = NULL;

            if (backend_nb->svc_mon_lrp->peer) {
                peer_switch_od = backend_nb->svc_mon_lrp->peer->od;
            }

            if (!peer_switch_od) {
                continue;
            }

We should also check the peer is actually a switch, i.e., something like:

if (!peer_switch_od
    || ovn_datapath_get_type(peer_switch_od) != DP_SWITCH) {
    continue;
}

>              if (!peer_switch_od) {
>                  continue;
>              }
> @@ -8580,7 +8580,7 @@ build_lb_health_check_response_lflows(
>              ds_clear(match);
>              ds_clear(action);
>  
> -            /* icmp6 type 1 and icmp4 type 3 are included as well, because
> +            /* icmp6 type 1 and icmp4 type 3 are included in the match, 
> because
>               * the controller is using them to detect unreachable ports. */
>              if (addr_is_ipv6(backend_nb->svc_mon_src_ip)) {
>                  ds_put_format(match,
> @@ -10464,23 +10464,9 @@ build_lswitch_arp_nd_local_svc_mon(const struct 
> ovn_lb_datapaths *lb_dps,
>                  continue;
>              }
>  
> -            /* ARP responder is necessary only if the service check is not
> -             * backed by a real port and an IP. */
> -            struct ovn_port *svc_mon_op;
> -            bool port_found = false;
> -            VECTOR_FOR_EACH (&op->od->router_ports, svc_mon_op) {
> -                if (!svc_mon_op->peer) {
> -                    continue;
> -                }
> -                const char *lrp_ip = lrp_find_member_ip(
> -                        svc_mon_op->peer,
> -                        backend_nb->svc_mon_src_ip);
> -                if (lrp_ip && !strcmp(lrp_ip, backend_nb->svc_mon_src_ip)) {
> -                    port_found = true;
> -                    break;
> -                }
> -            }
> -            if (port_found) {
> +            /* ARP responder is only needed if the service check is NOT
> +             * backed by a real LRP (i.e., using a reserved IP). */
> +            if (backend_nb->svc_mon_lrp) {
>                  continue;
>              }
>  

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

Reply via email to