On Wed, 2026-01-28 at 15:02 +0100, Dumitru Ceara wrote:
> 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.

Thanks for the review. I squashed this patch for the upcoming v4. I
just have few question below to clear things up before posting it.

> 
> 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?

Since we'll have a "setter" method for this member, called from outside
of the "init" function, is it OK to use `const` here?

> 
> >  };
> >  
> >  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.

I moved the block out of northd.c, as you suggested. I would like your
input on the function naming:

* `ovn_northd_lb_backend_set_mon_port` - more human readable
* `ovn_northd_lb_backend_set_svc_mon_op` - longer, but more exact

Do you have a preference, or other suggestions?

> 
> >                          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;
> }

ack. replaced.

Thanks again,
Martin.

> 
> >              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