On Wed, Feb 4, 2026 at 12:08 PM Alexandra Rukomoinikova
<[email protected]> wrote:

> This commit adds new 'ct_lb_mark_local' action to enable
> per‑chassis load balancing, action filters backends by local
> chassis bindings and builds OpenFlow groups containing only local backends.
> This mechanism will later support fully distributed load balancers.
>
> Suggested-by: Vladislav Odintsov <[email protected]>
> Signed-off-by: Alexandra Rukomoinikova <[email protected]>
> Acked-by: Lorenzo Bianconi <[email protected]>
> ---
> v6 --> v7: fixed Ales comments
> ---
>

Hi Alexandra,

thank you for v7. I have some small nits down below.


>  controller/lflow.c          |  17 +++++
>  controller/lflow.h          |   1 +
>  controller/ovn-controller.c |   1 +
>  include/ovn/actions.h       |  11 +++
>  lib/actions.c               | 145 ++++++++++++++++++++++++++++++------
>  lib/ovn-util.c              |   2 +-
>  tests/ovn.at                |  32 ++++++++
>  tests/test-ovn.c            |  11 +++
>  utilities/ovn-trace.c       |  14 +++-
>  9 files changed, 207 insertions(+), 27 deletions(-)
>
> diff --git a/controller/lflow.c b/controller/lflow.c
> index 915b24269..2bc389f08 100644
> --- a/controller/lflow.c
> +++ b/controller/lflow.c
> @@ -64,6 +64,7 @@ struct lookup_port_aux {
>      const struct sbrec_logical_flow *lflow;
>      struct objdep_mgr *deps_mgr;
>      const struct hmap *chassis_tunnels;
> +    const struct shash *local_bindings;
>  };
>
>  struct condition_aux {
> @@ -153,6 +154,20 @@ lookup_port_cb(const void *aux_, const char
> *port_name, unsigned int *portp)
>      return false;
>  }
>
> +/* Given the OVN port name, get true if port locates on local chassis,
> + * false otherwise. */
> +static bool
> +lookup_local_port_cb(const void *aux_, const char *port_name)
> +{
> +    const struct lookup_port_aux *aux = aux_;
> +
> +    if (local_binding_get_primary_pb(aux->local_bindings, port_name)) {
> +        return true;
> +    }
> +
> +    return false;
> +}
> +
>  /* Given the OVN port name, get its openflow port */
>  static bool
>  tunnel_ofport_cb(const void *aux_, const char *port_name, ofp_port_t
> *ofport)
> @@ -857,6 +872,7 @@ add_matches_to_flow_table(const struct
> sbrec_logical_flow *lflow,
>          .lflow = lflow,
>          .deps_mgr = l_ctx_out->lflow_deps_mgr,
>          .chassis_tunnels = l_ctx_in->chassis_tunnels,
> +        .local_bindings = l_ctx_in->lbinding_lports,
>      };
>
>      /* Parse any meter to be used if this flow should punt packets to
> @@ -871,6 +887,7 @@ add_matches_to_flow_table(const struct
> sbrec_logical_flow *lflow,
>      struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
>      struct ovnact_encode_params ep = {
>          .lookup_port = lookup_port_cb,
> +        .lookup_local_port = lookup_local_port_cb,
>          .tunnel_ofport = tunnel_ofport_cb,
>          .aux = &aux,
>          .is_switch = ldp->is_switch,
> diff --git a/controller/lflow.h b/controller/lflow.h
> index 30c6dbebd..cd714ffef 100644
> --- a/controller/lflow.h
> +++ b/controller/lflow.h
> @@ -138,6 +138,7 @@ struct lflow_ctx_in {
>      const struct smap *template_vars;
>      const struct flow_collector_ids *collector_ids;
>      const struct hmap *local_lbs;
> +    const struct shash *lbinding_lports;
>      bool localnet_learn_fdb;
>      bool localnet_learn_fdb_changed;
>      bool explicit_arp_ns_output;
> diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> index 2d9b3e033..cd3ef616c 100644
> --- a/controller/ovn-controller.c
> +++ b/controller/ovn-controller.c
> @@ -3898,6 +3898,7 @@ init_lflow_ctx(struct engine_node *node,
>      l_ctx_in->template_vars = &template_vars->local_templates;
>      l_ctx_in->collector_ids = &fo->collector_ids;
>      l_ctx_in->local_lbs = &lb_data->local_lbs;
> +    l_ctx_in->lbinding_lports = &rt_data->lbinding_data.bindings;
>
>      l_ctx_out->flow_table = &fo->flow_table;
>      l_ctx_out->group_table = &fo->group_table;
> diff --git a/include/ovn/actions.h b/include/ovn/actions.h
> index d3f0bfd04..2ca8dac8f 100644
> --- a/include/ovn/actions.h
> +++ b/include/ovn/actions.h
> @@ -75,6 +75,7 @@ struct collector_set_ids;
>      OVNACT(CT_SNAT_IN_CZONE,  ovnact_ct_nat)          \
>      OVNACT(CT_LB,             ovnact_ct_lb)           \
>      OVNACT(CT_LB_MARK,        ovnact_ct_lb)           \
> +    OVNACT(CT_LB_MARK_LOCAL,  ovnact_ct_lb)           \
>      OVNACT(SELECT,            ovnact_select)          \
>      OVNACT(CT_CLEAR,          ovnact_null)            \
>      OVNACT(CT_COMMIT_NAT,     ovnact_ct_commit_to_zone) \
> @@ -311,6 +312,12 @@ struct ovnact_ct_commit_to_zone {
>      uint8_t ltable;
>  };
>
> +enum ovnact_ct_lb_type {
> +    OVNACT_CT_LB_TYPE_LABEL,
> +    OVNACT_CT_LB_TYPE_MARK,
> +    OVNACT_CT_LB_LOCAL_TYPE_MARK,
> +};
> +
>  enum ovnact_ct_lb_flag {
>      OVNACT_CT_LB_FLAG_NONE,
>      OVNACT_CT_LB_FLAG_SKIP_SNAT,
> @@ -324,6 +331,7 @@ struct ovnact_ct_lb_dst {
>          ovs_be32 ipv4;
>      };
>      uint16_t port;
> +    char *port_name;
>  };
>
>  /* OVNACT_CT_LB/OVNACT_CT_LB_MARK. */
> @@ -891,6 +899,9 @@ struct ovnact_encode_params {
>      bool (*lookup_port)(const void *aux, const char *port_name,
>                          unsigned int *portp);
>
> +    /* Check if the logical port is bound to this chassis. */
> +    bool (*lookup_local_port)(const void *aux, const char *port_name);
> +
>      /* Looks up tunnel port to a chassis by its port name.  If found,
> stores
>       * its openflow port number in '*ofport' and returns true;
>       * otherwise, returns false. */
> diff --git a/lib/actions.c b/lib/actions.c
> index a2e389701..ecef81493 100644
> --- a/lib/actions.c
> +++ b/lib/actions.c
> @@ -1187,8 +1187,25 @@ ovnact_ct_commit_to_zone_free(struct
> ovnact_ct_commit_to_zone *cn OVS_UNUSED)
>  {
>  }
>
> +
> +static bool
> +parse_ct_lb_logical_port_name(struct action_context *ctx,
> +                              struct ovnact_ct_lb_dst *dst)
> +{
> +    if (ctx->lexer->token.type != LEX_T_STRING) {
> +        return false;
> +    }
> +
> +    dst->port_name = xstrdup(ctx->lexer->token.s);
> +
> +    lexer_get(ctx->lexer);
> +
> +    return true;
> +}
> +
>  static void
> -parse_ct_lb_action(struct action_context *ctx, bool ct_lb_mark)
> +parse_ct_lb_action(struct action_context *ctx,
> +                   enum ovnact_ct_lb_type type)
>  {
>      if (ctx->pp->cur_ltable >= ctx->pp->n_tables) {
>          lexer_error(ctx->lexer, "\"ct_lb\" action not allowed in last
> table.");
> @@ -1211,7 +1228,19 @@ parse_ct_lb_action(struct action_context *ctx, bool
> ct_lb_mark)
>
>          while (!lexer_match(ctx->lexer, LEX_T_SEMICOLON) &&
>                 !lexer_match(ctx->lexer, LEX_T_RPAREN)) {
> -            struct ovnact_ct_lb_dst dst;
> +            struct ovnact_ct_lb_dst dst = {0};
> +
> +            if (type == OVNACT_CT_LB_LOCAL_TYPE_MARK) {
> +                if (!parse_ct_lb_logical_port_name(ctx, &dst)) {
> +                    vector_destroy(&dsts);
> +                    lexer_syntax_error(ctx->lexer,
> +                                       "expecting logical port name "
> +                                       "for distributed load balancer");
> +                    return;
> +                }
> +                lexer_match(ctx->lexer, LEX_T_COLON);
>

nit: Should be lexer_force_match(...).


> +            }
> +
>              if (lexer_match(ctx->lexer, LEX_T_LSQUARE)) {
>                  /* IPv6 address and port */
>                  if (ctx->lexer->token.type != LEX_T_INTEGER
> @@ -1298,8 +1327,21 @@ parse_ct_lb_action(struct action_context *ctx, bool
> ct_lb_mark)
>          }
>      }
>
> -    struct ovnact_ct_lb *cl = ct_lb_mark ?
> ovnact_put_CT_LB_MARK(ctx->ovnacts)
> -                                         : ovnact_put_CT_LB(ctx->ovnacts);
> +    struct ovnact_ct_lb *cl;
> +    switch (type) {
> +        case OVNACT_CT_LB_TYPE_LABEL:
> +            cl = ovnact_put_CT_LB(ctx->ovnacts);
> +            break;
> +        case OVNACT_CT_LB_TYPE_MARK:
> +            cl = ovnact_put_CT_LB_MARK(ctx->ovnacts);
> +            break;
> +        case OVNACT_CT_LB_LOCAL_TYPE_MARK:
> +            cl = ovnact_put_CT_LB_MARK_LOCAL(ctx->ovnacts);
> +            break;
> +        default:
> +            OVS_NOT_REACHED();
> +    }
> +
>      cl->ltable = ctx->pp->cur_ltable + 1;
>      cl->n_dsts = vector_len(&dsts);
>      cl->dsts = vector_steal_array(&dsts);
> @@ -1308,13 +1350,16 @@ parse_ct_lb_action(struct action_context *ctx,
> bool ct_lb_mark)
>  }
>
>  static void
> -format_ct_lb(const struct ovnact_ct_lb *cl, struct ds *s, bool ct_lb_mark)
> +format_ct_lb(const struct ovnact_ct_lb *cl, struct ds *s,
> +             enum ovnact_ct_lb_type type)
>  {
> -    if (ct_lb_mark) {
> -        ds_put_cstr(s, "ct_lb_mark");
> -    } else {
> -        ds_put_cstr(s, "ct_lb");
> -    }
> +    static const char *const lb_action_strings[] = {
> +        [OVNACT_CT_LB_TYPE_LABEL] = "ct_lb",
> +        [OVNACT_CT_LB_TYPE_MARK] = "ct_lb_mark",
> +        [OVNACT_CT_LB_LOCAL_TYPE_MARK] = "ct_lb_mark_local",
> +    };
> +    ds_put_cstr(s, lb_action_strings[type]);
> +
>      if (cl->n_dsts) {
>          ds_put_cstr(s, "(backends=");
>          for (size_t i = 0; i < cl->n_dsts; i++) {
> @@ -1323,6 +1368,9 @@ format_ct_lb(const struct ovnact_ct_lb *cl, struct
> ds *s, bool ct_lb_mark)
>              }
>
>              const struct ovnact_ct_lb_dst *dst = &cl->dsts[i];
> +            if (type == OVNACT_CT_LB_LOCAL_TYPE_MARK) {
> +                ds_put_format(s, "\"%s\":", dst->port_name);
> +            }
>              if (dst->family == AF_INET) {
>                  ds_put_format(s, IP_FMT, IP_ARGS(dst->ipv4));
>                  if (dst->port) {
> @@ -1363,20 +1411,26 @@ format_ct_lb(const struct ovnact_ct_lb *cl, struct
> ds *s, bool ct_lb_mark)
>  static void
>  format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s)
>  {
> -    format_ct_lb(cl, s, false);
> +    format_ct_lb(cl, s, OVNACT_CT_LB_TYPE_LABEL);
>  }
>
>  static void
>  format_CT_LB_MARK(const struct ovnact_ct_lb *cl, struct ds *s)
>  {
> -    format_ct_lb(cl, s, true);
> +    format_ct_lb(cl, s, OVNACT_CT_LB_TYPE_MARK);
> +}
> +
> +static void
> +format_CT_LB_MARK_LOCAL(const struct ovnact_ct_lb *cl, struct ds *s)
> +{
> +    format_ct_lb(cl, s, OVNACT_CT_LB_LOCAL_TYPE_MARK);
>  }
>
>  static void
>  encode_ct_lb(const struct ovnact_ct_lb *cl,
>               const struct ovnact_encode_params *ep,
>               struct ofpbuf *ofpacts,
> -             bool ct_lb_mark)
> +             enum ovnact_ct_lb_type type)
>  {
>      uint8_t recirc_table = cl->ltable + first_ptable(ep, ep->pipeline);
>      if (!cl->n_dsts) {
> @@ -1408,7 +1462,8 @@ encode_ct_lb(const struct ovnact_ct_lb *cl,
>      struct ofpact_group *og;
>      uint32_t zone_reg = ep->is_switch ? MFF_LOG_CT_ZONE - MFF_REG0
>                              : MFF_LOG_DNAT_ZONE - MFF_REG0;
> -    const char *flag_reg = ct_lb_mark ? "ct_mark" : "ct_label";
> +    const char *flag_reg = (type == OVNACT_CT_LB_TYPE_LABEL)
> +                            ? "ct_label" : "ct_mark";
>
>      const char *ct_flag_value;
>      switch (cl->ct_flag) {
> @@ -1435,32 +1490,55 @@ encode_ct_lb(const struct ovnact_ct_lb *cl,
>      BUILD_ASSERT(MFF_LOG_CT_ZONE < MFF_REG0 + FLOW_N_REGS);
>      BUILD_ASSERT(MFF_LOG_DNAT_ZONE >= MFF_REG0);
>      BUILD_ASSERT(MFF_LOG_DNAT_ZONE < MFF_REG0 + FLOW_N_REGS);
> +
> +    size_t n_active_backends = 0;
>      for (size_t bucket_id = 0; bucket_id < cl->n_dsts; bucket_id++) {
>          const struct ovnact_ct_lb_dst *dst = &cl->dsts[bucket_id];
>          char ip_addr[INET6_ADDRSTRLEN];
> +
> +        if (type == OVNACT_CT_LB_LOCAL_TYPE_MARK
> +            && !ep->lookup_local_port(ep->aux, dst->port_name)) {
> +            continue;
> +        }
> +
>          if (dst->family == AF_INET) {
>              inet_ntop(AF_INET, &dst->ipv4, ip_addr, sizeof ip_addr);
>          } else {
>              inet_ntop(AF_INET6, &dst->ipv6, ip_addr, sizeof ip_addr);
>          }
> -        ds_put_format(&ds,
> ",bucket=bucket_id=%"PRIuSIZE",weight:100,actions="
> -                      "ct(nat(dst=%s%s%s", bucket_id,
> -                      dst->family == AF_INET6 && dst->port ? "[" : "",
> -                      ip_addr,
> -                      dst->family == AF_INET6 && dst->port ? "]" : "");
> +
> +        ds_put_format(&ds,
> ",bucket=bucket_id=%"PRIuSIZE",weight:100,actions=",
> +                      bucket_id);
> +
> +        bool is_ipv6_address = (dst->family == AF_INET6 && dst->port);
> +        ds_put_format(&ds, "ct(nat(dst=");
> +        if (is_ipv6_address) {
> +            ds_put_format(&ds, "[%s]", ip_addr);
> +        } else {
> +            ds_put_format(&ds, "%s", ip_addr);
> +        }
> +
>          if (dst->port) {
>              ds_put_format(&ds, ":%"PRIu16, dst->port);
>          }
> +
>

nit: Unrelated change.


>          ds_put_format(&ds, "),commit,table=%d,zone=NXM_NX_REG%d[0..15],"
>                        "exec(set_field:"
>                          OVN_CT_MASKED_STR(OVN_CT_NATTED)
>                        "->%s",
>                        recirc_table, zone_reg, flag_reg);
> +
>

nit: Unrelated change.


>          if (ct_flag_value) {
>              ds_put_format(&ds, ",set_field:%s->%s", ct_flag_value,
> flag_reg);
>          }
>
>          ds_put_cstr(&ds, "))");
> +
> +        n_active_backends++;
> +    }
> +
> +    if (!n_active_backends) {
> +        return;
>      }
>
>      table_id = ovn_extend_table_assign_id(ep->group_table, ds_cstr(&ds),
> @@ -1480,7 +1558,7 @@ encode_CT_LB(const struct ovnact_ct_lb *cl,
>               const struct ovnact_encode_params *ep,
>               struct ofpbuf *ofpacts)
>  {
> -    encode_ct_lb(cl, ep, ofpacts, false);
> +    encode_ct_lb(cl, ep, ofpacts, OVNACT_CT_LB_TYPE_LABEL);
>  }
>
>  static void
> @@ -1488,13 +1566,30 @@ encode_CT_LB_MARK(const struct ovnact_ct_lb *cl,
>                    const struct ovnact_encode_params *ep,
>                    struct ofpbuf *ofpacts)
>  {
> -    encode_ct_lb(cl, ep, ofpacts, true);
> +    encode_ct_lb(cl, ep, ofpacts, OVNACT_CT_LB_TYPE_MARK);
>  }
>
>  static void
> -ovnact_ct_lb_free(struct ovnact_ct_lb *ct_lb)
> +encode_CT_LB_MARK_LOCAL(const struct ovnact_ct_lb *cl,
> +                        const struct ovnact_encode_params *ep,
> +                        struct ofpbuf *ofpacts)
> +{
> +    encode_ct_lb(cl, ep, ofpacts, OVNACT_CT_LB_LOCAL_TYPE_MARK);
> +}
> +
> +static void
> +ovnact_ct_lb_free_dsts(struct ovnact_ct_lb *ct_lb)
>  {
> +    for (size_t i = 0; i < ct_lb->n_dsts; i++) {
> +        free(ct_lb->dsts[i].port_name);
> +    }
>      free(ct_lb->dsts);
> +}
> +
> +static void
> +ovnact_ct_lb_free(struct ovnact_ct_lb *ct_lb)
> +{
> +    ovnact_ct_lb_free_dsts(ct_lb);
>      free(ct_lb->hash_fields);
>  }
>
> @@ -5905,9 +6000,11 @@ parse_action(struct action_context *ctx)
>      } else if (lexer_match_id(ctx->lexer, "ct_lb")) {
>          VLOG_WARN_RL(&rl, "The \"ct_lb\" action is deprecated please "
>                            "consider using a different action.");
> -        parse_ct_lb_action(ctx, false);
> +        parse_ct_lb_action(ctx, OVNACT_CT_LB_TYPE_LABEL);
>      } else if (lexer_match_id(ctx->lexer, "ct_lb_mark")) {
> -        parse_ct_lb_action(ctx, true);
> +        parse_ct_lb_action(ctx, OVNACT_CT_LB_TYPE_MARK);
> +    } else if (lexer_match_id(ctx->lexer, "ct_lb_mark_local")) {
> +        parse_ct_lb_action(ctx, OVNACT_CT_LB_LOCAL_TYPE_MARK);
>      } else if (lexer_match_id(ctx->lexer, "ct_clear")) {
>          ovnact_put_CT_CLEAR(ctx->ovnacts);
>      } else if (lexer_match_id(ctx->lexer, "ct_commit_nat")) {
> diff --git a/lib/ovn-util.c b/lib/ovn-util.c
> index 71098d478..4ee500590 100644
> --- a/lib/ovn-util.c
> +++ b/lib/ovn-util.c
> @@ -967,7 +967,7 @@ ip_address_and_port_from_lb_key(const char *key, char
> **ip_address,
>   *
>   * NOTE: If OVN_NORTHD_PIPELINE_CSUM is updated make sure to double check
>   * whether an update of OVN_INTERNAL_MINOR_VER is required. */
> -#define OVN_NORTHD_PIPELINE_CSUM "2164662054 10958"
> +#define OVN_NORTHD_PIPELINE_CSUM "4239189964 11014"
>  #define OVN_INTERNAL_MINOR_VER 11
>
>  /* Returns the OVN version. The caller must free the returned value. */
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 84d37dfdf..3dd09ef6c 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -2375,6 +2375,38 @@ mirror("lsp1");
>  mirror(lsp1);
>      Syntax error at `lsp1' expecting port name string.
>
> +ct_lb_mark_local(backends="lsp1":192.168.0.101);
> +    encodes as group:25
> +    uses group: id(25),
> name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=192.168.0.101),commit,table=19,zone=NXM_NX_REG13[[0..15]],exec(set_field:2/2->ct_mark)))
> +    has prereqs ip
> +
> +ct_lb_mark_local(backends="lsp1":192.168.0.101:10880);
> +    encodes as group:26
> +    uses group: id(26),
> name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=
> 192.168.0.101:10880
> ),commit,table=oflow_in_table,zone=NXM_NX_REG13[[0..15]],exec(set_field:2/2->ct_mark)))
> +    has prereqs ip
> +
> +ct_lb_mark_local(backends="lsp1":192.168.0.101:10880;
> hash_fields="eth_src,eth_dst,ip_src,ip_dst,sctp_src,sctp_dst");
> +    encodes as group:27
> +    uses group: id(27),
> name(type=select,selection_method=hash,fields(eth_src,eth_dst,ip_src,ip_dst,sctp_src,sctp_dst),bucket=bucket_id=0,weight:100,actions=ct(nat(dst=
> 192.168.0.101:10880
> ),commit,table=oflow_in_table,zone=NXM_NX_REG13[[0..15]],exec(set_field:2/2->ct_mark)))
> +    has prereqs ip
> +
> +ct_lb_mark_local(backends=192.168.0.101:80);
> +    Syntax error at `192.168.0.101' expecting logical port name for
> distributed load balancer.
> +
> +ct_lb_mark_local(backends=lsp1:192.168.0.101:10880);
> +    Syntax error at `lsp1' expecting logical port name for distributed
> load balancer.
> +
> +# add hash fields parsing
> +ct_lb_mark_local(backends="lsp1":fd0f::2);
> +    encodes as group:28
> +    uses group: id(28),
> name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=fd0f::2),commit,table=19,zone=NXM_NX_REG13[[0..15]],exec(set_field:2/2->ct_mark)))
> +    has prereqs ip
> +
> +ct_lb_mark_local(backends="lsp1":[[fd0f::2]]:80);
> +    encodes as group:29
> +    uses group: id(29),
> name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=[[fd0f::2]]:80),commit,table=19,zone=NXM_NX_REG13[[0..15]],exec(set_field:2/2->ct_mark)))
> +    has prereqs ip
> +
>  # Miscellaneous negative tests.
>  ;
>      Syntax error at `;'.
> diff --git a/tests/test-ovn.c b/tests/test-ovn.c
> index fae7e7bd5..1132714f6 100644
> --- a/tests/test-ovn.c
> +++ b/tests/test-ovn.c
> @@ -265,6 +265,16 @@ lookup_port_cb(const void *ports_, const char
> *port_name, unsigned int *portp)
>      return true;
>  }
>
> +static bool
> +lookup_local_port_cb(const void *ports_, const char *port_name)
> +{
> +    const struct simap *ports = ports_;
> +    const struct simap_node *node = simap_find(ports, port_name);
> +
> +
> +    return node ? true : false;
>

nit: We could return !!simap_find(...).


> +}
> +
>  static bool
>  lookup_tunnel_ofport(const void *ports_, const char *port_name,
>                       ofp_port_t *ofport)
> @@ -1361,6 +1371,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx
> OVS_UNUSED)
>              /* Encode the actions into OpenFlow and print. */
>              const struct ovnact_encode_params ep = {
>                  .lookup_port = lookup_port_cb,
> +                .lookup_local_port = lookup_local_port_cb,
>                  .tunnel_ofport = lookup_tunnel_ofport,
>                  .aux = &ports,
>                  .is_switch = true,
> diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
> index 3e87acc6a..8708a50c3 100644
> --- a/utilities/ovn-trace.c
> +++ b/utilities/ovn-trace.c
> @@ -2675,9 +2675,13 @@ execute_ct_lb(const struct ovnact_ct_lb *ct_lb,
>          ct_lb_flow.ct_state |= next_ct_state(&comment);
>      }
>
> +    const char *action_type =
> +        ct_lb->ovnact.type == OVNACT_CT_LB_MARK ? "ct_lb_mark" :
> +        ct_lb->ovnact.type == OVNACT_CT_LB_MARK_LOCAL ?
> "ct_lb_mark_local" :
> +        "ct_lb";
> +

     struct ovntrace_node *node = ovntrace_node_append(
> -        super, OVNTRACE_NODE_TRANSFORMATION, "%s%s",
> -        ct_lb->ovnact.type == OVNACT_CT_LB_MARK ? "ct_lb_mark" : "ct_lb",
> +        super, OVNTRACE_NODE_TRANSFORMATION, "%s%s", action_type,
>          ds_cstr_ro(&comment));
>      ds_destroy(&comment);
>
> @@ -3334,6 +3338,12 @@ trace_actions(const struct ovnact *ovnacts, size_t
> ovnacts_len,
>                            super);
>              break;
>
> +        case OVNACT_CT_LB_MARK_LOCAL:
> +            /* Treat all ports as local. */
> +            execute_ct_lb(ovnact_get_CT_LB_MARK_LOCAL(a), dp, uflow,
> +                          pipeline, super);
> +            break;
> +
>          case OVNACT_SELECT:
>              execute_select(ovnact_get_SELECT(a), dp, uflow,
>                                     pipeline, super);
> --
> 2.48.1
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev


I took care of the nits and merged this into main.

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

Reply via email to