On 1/19/26 8:39 PM, Lucas Vargas Dias via dev wrote:
> FIN or FIN-ACK packets from client was dropping because the client
> side was using conntrack. Connection is in SYN_SENT state because the
> response from backends bypass the conntrack, when client sends a FIN
> or FIN-ACK, the conntrack is invalid and packet is dropped.
> To fix it, remove the client side from conntrack, calculating the hash
> from packet to choice the backend.
> REG_IDX_LB_STATELESS is used to store the index from backend.
> 
> Signed-off-by: Lucas Vargas Dias <[email protected]>
> ---

Hi Lucas,

Thanks for the backport!

>  northd/lb.c         |   3 +
>  northd/lb.h         |   2 +
>  northd/northd.c     | 281 +++++++++++++++++++++++++++++++-------------
>  tests/multinode.at  |  99 ++++++++++------
>  tests/ovn-northd.at | 217 ++++++++++++++++++++++++++++++++--
>  5 files changed, 473 insertions(+), 129 deletions(-)
> 
> diff --git a/northd/lb.c b/northd/lb.c
> index af0c92954..ef92249ce 100644
> --- a/northd/lb.c
> +++ b/northd/lb.c
> @@ -296,6 +296,9 @@ ovn_northd_lb_init(struct ovn_northd_lb *lb,
>      }
>      lb->affinity_timeout = affinity_timeout;
>  
> +    lb->use_stateless_nat = smap_get_bool(&nbrec_lb->options,
> +                                          "use_stateless_nat", false);
> +
>      sset_init(&lb->ips_v4);
>      sset_init(&lb->ips_v6);
>      struct smap_node *node;
> diff --git a/northd/lb.h b/northd/lb.h
> index aa6616af4..4696b4d98 100644
> --- a/northd/lb.h
> +++ b/northd/lb.h
> @@ -72,6 +72,8 @@ struct ovn_northd_lb {
>  
>      /* Indicates if the load balancer has health checks configured. */
>      bool health_checks;
> +
> +    bool use_stateless_nat;
>  };
>  
>  /* ovn-northd specific backend information. */
> diff --git a/northd/northd.c b/northd/northd.c
> index f6559c240..5c78f322e 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -149,6 +149,7 @@ static bool vxlan_ic_mode;
>  #define REG_LB_IPV4 "reg4"
>  #define REG_LB_IPV6 "xxreg1"
>  #define REG_LB_PORT "reg2[0..15]"
> +#define REG_IDX_LB_STATELESS "reg1[0..15]"
>  
>  /* Registers for ACL evaluation */
>  #define REGBIT_ACL_VERDICT_ALLOW "reg8[16]"
> @@ -12021,6 +12022,154 @@ lrouter_use_common_zone(const struct ovn_datapath 
> *od)
>      return !od->is_gw_router && use_common_zone;
>  }
>  
> +static void
> +build_lrouter_flows_for_lb_stateless(struct lrouter_nat_lb_flows_ctx *ctx,
> +                                     struct ovn_datapath *od,
> +                                     struct lflow_ref *lflow_ref,
> +                                     struct ovn_port *dgp,
> +                                     const char *meter)
> +{
> +    /* (NOTE) dnat_action: Add a new rule lr_in_dnat with backend IP
> +     * and port action to skip conntrack completely. It is based on
> +     * REG_IDX_LB_STATELESS which was calculated in lr_in_defrag.
> +     * So, if the packet has VIP IP destination and port
> +     * (if port was configured), it selects a backend based on
> +     * REG_IDX_LB_STATELESS. It works to multi-chassis and avoid to
> +     * sync conntrack between them.
> +     */
> +    struct ds new_action_stateless_nat = DS_EMPTY_INITIALIZER;
> +    struct ds new_match_stateless_nat = DS_EMPTY_INITIALIZER;
> +    if (ctx->lb_vip->n_backends ||
> +        !ctx->lb_vip->empty_backend_rej) {
> +        ds_put_format(&new_match_stateless_nat, "is_chassis_resident(%s)",
> +                      dgp->cr_port->json_key);
> +    }
> +
> +    bool ipv4 = ctx->lb_vip->address_family == AF_INET;
> +    const char *ip_match = ipv4 ? "ip4" : "ip6";
> +    ds_put_format(&new_match_stateless_nat, " && %s && %s.dst == %s",
> +                  ip_match, ip_match, ctx->lb_vip->vip_str);
> +    if (ctx->lb_vip->port_str) {
> +        ds_put_format(&new_match_stateless_nat,
> +                      " && %s && %s.dst == %s",
> +                      ctx->lb->proto, ctx->lb->proto,
> +                      ctx->lb_vip->port_str);
> +    }
> +
> +    const struct ovn_lb_backend *backend;
> +    if (ctx->lb_vip->n_backends == 1) {
> +        backend = &ctx->lb_vip->backends[0];
> +        ds_put_format(&new_action_stateless_nat, "%s.dst = %s; ",
> +                      ip_match, backend->ip_str);
> +        if (ctx->lb_vip->port_str) {
> +            ds_put_format(&new_action_stateless_nat, "%s.dst = %s; ",
> +                          ctx->lb->proto, backend->port_str);
> +        }
> +        ds_put_format(&new_action_stateless_nat, "next;");
> +        ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT,
> +                                  ctx->prio,
> +                                  ds_cstr(&new_match_stateless_nat),
> +                                  ds_cstr(&new_action_stateless_nat),
> +                                  NULL, meter, &ctx->lb->nlb->header_,
> +                                  lflow_ref);
> +    }
> +    size_t match_len = new_match_stateless_nat.length;
> +
> +    size_t i = 0;
> +    for (; i < ctx->lb_vip->n_backends; i++) {

Nit: 'size_t i = 0' can be moved inside the 'for'.

I took care of this and applied the patch to 25.03.

Regards,
Dumitru

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

Reply via email to