On Wed, Jul 23, 2025 at 6:23 AM Mark Michelson <mmich...@redhat.com> wrote:

> Hello Han,
>
> If callers of the ct_*() actions now need to do their own ct state
> filtering beforehand, do we really need two separate OF flows that check
> for ct.new and ct.est? Could we not just install a single OF flow that
> matches on ct.trk?


Hi Mark,

I thought the same way, but it turned out that the ct state is a must have
as prerequisite.

Thanks,
Han

>
>
> On 7/16/25 3:07 AM, Han Zhou wrote:
> > The ct_nw_dst(), ct_ip6_dst(), and ct_tp_dst() logical actions are
> > implemented by jumping to physical flows in tables 81, 82, and 83
> > respectively. These physical flows previously only matched on
> > established connections (ct.trk && ct.est), limiting their use to
> > scenarios where connections were already established.
> >
> > Extend the physical flow matches to support both established and new
> > connection states by changing from:
> >    match = ct.trk && ct.est && ip4/ip6
> > to:
> >    match = ct.trk && (ct.est || ct.new) && ip4/ip6
> >
> > This allows the ct_xxx actions to work with new connections, while
> > maintaining compatibility with existing established connection use
> > cases.
> >
> > The responsibility for matching specific connection states (e.g., ct.est
> > for fragmented packet handling) is moved to the logical flows in
> > northd.c, providing more flexibility in how these actions are used
> > across different scenarios.
> >
> > Signed-off-by: Han Zhou <hz...@ovn.org>
> > ---
> >   controller/physical.c | 38 +++++++++++++++++++++++++++++++-------
> >   northd/northd.c       |  6 ++++--
> >   tests/ovn-northd.at   | 24 ++++++++++++------------
> >   3 files changed, 47 insertions(+), 21 deletions(-)
> >
> > diff --git a/controller/physical.c b/controller/physical.c
> > index 1cc4173b2b6b..7b9b66ffe7f4 100644
> > --- a/controller/physical.c
> > +++ b/controller/physical.c
> > @@ -3033,24 +3033,35 @@ physical_run(struct physical_ctx *p_ctx,
> >       add_default_drop_flow(p_ctx, OFTABLE_LOG_TO_PHY, flow_table);
> >
> >       /* Table 81, 82 and 83
> > -     * Match on ct.trk and ct.est and store the ct_nw_dst, ct_ip6_dst
> and
> > -     * ct_tp_dst in the registers. */
> > -    uint32_t ct_state = OVS_CS_F_TRACKED | OVS_CS_F_ESTABLISHED;
> > +     * Match on ct.trk and ct.est | ct.new and store the ct_nw_dst,
> ct_ip6_dst
> > +     * and ct_tp_dst in the registers. */
> > +    uint32_t ct_state_est = OVS_CS_F_TRACKED | OVS_CS_F_ESTABLISHED;
> > +    uint32_t ct_state_new = OVS_CS_F_TRACKED | OVS_CS_F_NEW;
> > +    struct match match_new = MATCH_CATCHALL_INITIALIZER;
> >       match_init_catchall(&match);
> >       ofpbuf_clear(&ofpacts);
> >
> > -    /* Add the flow:
> > +    /* Add the flows:
> >        * match = (ct.trk && ct.est), action = (reg8 = ct_tp_dst)
> >        * table = 83
> > +     * match = (ct.trk && ct.new), action = (reg8 = ct_tp_dst)
> > +     * table = 83
> >        */
> > -    match_set_ct_state_masked(&match, ct_state, ct_state);
> > +    match_set_ct_state_masked(&match, ct_state_est, ct_state_est);
> >       put_move(MFF_CT_TP_DST, 0,  MFF_LOG_CT_ORIG_TP_DST_PORT, 0, 16,
> &ofpacts);
> >       ofctrl_add_flow(flow_table, OFTABLE_CT_ORIG_TP_DST_LOAD, 100, 0,
> &match,
> >                       &ofpacts, hc_uuid);
> >
> > -    /* Add the flow:
> > +    match_set_ct_state_masked(&match_new, ct_state_new, ct_state_new);
> > +    put_move(MFF_CT_TP_DST, 0,  MFF_LOG_CT_ORIG_TP_DST_PORT, 0, 16,
> &ofpacts);
> > +    ofctrl_add_flow(flow_table, OFTABLE_CT_ORIG_TP_DST_LOAD, 100, 0,
> > +                    &match_new, &ofpacts, hc_uuid);
> > +
> > +    /* Add the flows:
> >        * match = (ct.trk && ct.est && ip4), action = (reg4 = ct_nw_dst)
> >        * table = 81
> > +     * match = (ct.trk && ct.new && ip4), action = (reg4 = ct_nw_dst)
> > +     * table = 81
> >        */
> >       ofpbuf_clear(&ofpacts);
> >       match_set_dl_type(&match, htons(ETH_TYPE_IP));
> > @@ -3058,9 +3069,16 @@ physical_run(struct physical_ctx *p_ctx,
> >       ofctrl_add_flow(flow_table, OFTABLE_CT_ORIG_NW_DST_LOAD, 100, 0,
> &match,
> >                       &ofpacts, hc_uuid);
> >
> > -    /* Add the flow:
> > +    match_set_dl_type(&match_new, htons(ETH_TYPE_IP));
> > +    put_move(MFF_CT_NW_DST, 0,  MFF_LOG_CT_ORIG_NW_DST_ADDR, 0, 32,
> &ofpacts);
> > +    ofctrl_add_flow(flow_table, OFTABLE_CT_ORIG_NW_DST_LOAD, 100, 0,
> > +                    &match_new, &ofpacts, hc_uuid);
> > +
> > +    /* Add the flows:
> >        * match = (ct.trk && ct.est && ip6), action = (xxreg0 =
> ct_ip6_dst)
> >        * table = 82
> > +     * match = (ct.trk && ct.new && ip6), action = (xxreg0 =
> ct_ip6_dst)
> > +     * table = 82
> >        */
> >       ofpbuf_clear(&ofpacts);
> >       match_set_dl_type(&match, htons(ETH_TYPE_IPV6));
> > @@ -3069,6 +3087,12 @@ physical_run(struct physical_ctx *p_ctx,
> >       ofctrl_add_flow(flow_table, OFTABLE_CT_ORIG_IP6_DST_LOAD, 100, 0,
> &match,
> >                       &ofpacts, hc_uuid);
> >
> > +    match_set_dl_type(&match_new, htons(ETH_TYPE_IPV6));
> > +    put_move(MFF_CT_IPV6_DST, 0,  MFF_LOG_CT_ORIG_IP6_DST_ADDR, 0,
> > +             128, &ofpacts);
> > +    ofctrl_add_flow(flow_table, OFTABLE_CT_ORIG_IP6_DST_LOAD, 100, 0,
> > +                    &match_new, &ofpacts, hc_uuid);
> > +
> >       /* Implement the ct_state_save() logical action. */
> >
> >       /* Add the flow:
> > diff --git a/northd/northd.c b/northd/northd.c
> > index 9b21786fad05..b46895bfafbb 100644
> > --- a/northd/northd.c
> > +++ b/northd/northd.c
> > @@ -8731,12 +8731,14 @@ build_lb_hairpin(const struct ls_stateful_record
> *ls_stateful_rec,
> >            * We need to find a better way to handle the fragmented
> packets.
> >            * */
> >           ovn_lflow_add(lflows, od, S_SWITCH_IN_LB, 110,
> > -                      "ct.trk && !ct.rpl && "REGBIT_IP_FRAG" == 1 &&
> ip4",
> > +                      "ct.trk && ct.est && !ct.rpl && "REGBIT_IP_FRAG
> > +                      " == 1 && ip4",
> >                         REG_LB_IPV4 " = ct_nw_dst(); "
> >                         REG_LB_PORT " = ct_tp_dst(); next;",
> >                         lflow_ref);
> >           ovn_lflow_add(lflows, od, S_SWITCH_IN_LB, 110,
> > -                      "ct.trk && !ct.rpl && "REGBIT_IP_FRAG" == 1 &&
> ip6",
> > +                      "ct.trk && ct.est && !ct.rpl && "REGBIT_IP_FRAG
> > +                      " == 1 && ip6",
> >                         REG_LB_IPV6 " = ct_ip6_dst(); "
> >                         REG_LB_PORT " = ct_tp_dst(); next;",
> >                         lflow_ref);
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index 5e0747fcc816..3a353368a92f 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -4789,8 +4789,8 @@ check_stateful_flows() {
> >
> >       AT_CHECK([grep "ls_in_lb " sw0flows | ovn_strip_lflows], [0], [dnl
> >     table=??(ls_in_lb           ), priority=0    , match=(1),
> action=(next;)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 = ct_ip6_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 =
> ct_ip6_dst(); reg2[[0..15]] = ct_tp_dst(); next;)
> >     table=??(ls_in_lb           ), priority=120  , match=(ct.new &&
> ip4.dst == 10.0.0.10 && ct_tcp.dst == 80), action=(reg4 = 10.0.0.10;
> reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.4:8080);)
> >     table=??(ls_in_lb           ), priority=120  , match=(ct.new &&
> ip4.dst == 10.0.0.20 && ct_tcp.dst == 80), action=(reg4 = 10.0.0.20;
> reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.40:8080);)
> >   ])
> > @@ -4897,8 +4897,8 @@ check ovn-nbctl --wait=sb ls-lb-add sw0 lb1
> >   AT_CHECK([ovn-sbctl dump-flows sw0 | grep "ls_in_lb " |
> ovn_strip_lflows ], [0], [dnl
> >     table=??(ls_in_lb           ), priority=0    , match=(1),
> action=(next;)
> >     table=??(ls_in_lb           ), priority=110  , match=(ct.new &&
> ip4.dst == 10.0.0.20), action=(drop;)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 = ct_ip6_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 =
> ct_ip6_dst(); reg2[[0..15]] = ct_tp_dst(); next;)
> >   ])
> >
> >   AT_CLEANUP
> > @@ -8149,8 +8149,8 @@ AT_CHECK([grep -e "ls_in_acl.*eval" -e
> "ls_in_acl_hint" lsflows | ovn_strip_lflo
> >   AT_CHECK([grep -e "ls_in_lb " lsflows | ovn_strip_lflows], [0], [dnl
> >     table=??(ls_in_lb           ), priority=0    , match=(1),
> action=(next;)
> >     table=??(ls_in_lb           ), priority=110  , match=(ct.new &&
> ip4.dst == 10.0.0.2), action=(reg4 = 10.0.0.2;
> ct_lb_mark(backends=10.0.0.10);)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 = ct_ip6_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 =
> ct_ip6_dst(); reg2[[0..15]] = ct_tp_dst(); next;)
> >   ])
> >
> >   AT_CHECK([grep -e "ls_in_stateful" lsflows | ovn_strip_lflows], [0],
> [dnl
> > @@ -8208,8 +8208,8 @@ AT_CHECK([grep -e "ls_in_acl.*eval" -e
> "ls_in_acl_hint" lsflows | ovn_strip_lflo
> >   AT_CHECK([grep -e "ls_in_lb " lsflows | ovn_strip_lflows], [0], [dnl
> >     table=??(ls_in_lb           ), priority=0    , match=(1),
> action=(next;)
> >     table=??(ls_in_lb           ), priority=110  , match=(ct.new &&
> ip4.dst == 10.0.0.2), action=(reg4 = 10.0.0.2;
> ct_lb_mark(backends=10.0.0.10);)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 = ct_ip6_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 =
> ct_ip6_dst(); reg2[[0..15]] = ct_tp_dst(); next;)
> >   ])
> >
> >   AT_CHECK([grep -e "ls_in_stateful" lsflows | ovn_strip_lflows], [0],
> [dnl
> > @@ -8267,8 +8267,8 @@ AT_CHECK([grep -e "ls_in_acl.*eval" -e
> "ls_in_acl_hint" lsflows | ovn_strip_lflo
> >   AT_CHECK([grep -e "ls_in_lb " lsflows | ovn_strip_lflows], [0], [dnl
> >     table=??(ls_in_lb           ), priority=0    , match=(1),
> action=(next;)
> >     table=??(ls_in_lb           ), priority=110  , match=(ct.new &&
> ip4.dst == 10.0.0.2), action=(reg4 = 10.0.0.2;
> ct_lb_mark(backends=10.0.0.10);)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 = ct_ip6_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 =
> ct_ip6_dst(); reg2[[0..15]] = ct_tp_dst(); next;)
> >   ])
> >
> >   AT_CHECK([grep -e "ls_in_stateful" lsflows | ovn_strip_lflows], [0],
> [dnl
> > @@ -9800,8 +9800,8 @@ AT_CHECK([grep "ls_in_lb_aff_check" S0flows |
> ovn_strip_lflows], [0], [dnl
> >   ])
> >   AT_CHECK([grep "ls_in_lb " S0flows | ovn_strip_lflows], [0], [dnl
> >     table=??(ls_in_lb           ), priority=0    , match=(1),
> action=(next;)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > -  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 = ct_ip6_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip4), action=(reg4 = ct_nw_dst();
> reg2[[0..15]] = ct_tp_dst(); next;)
> > +  table=??(ls_in_lb           ), priority=110  , match=(ct.trk &&
> ct.est && !ct.rpl && reg0[[19]] == 1 && ip6), action=(xxreg1 =
> ct_ip6_dst(); reg2[[0..15]] = ct_tp_dst(); next;)
> >     table=??(ls_in_lb           ), priority=120  , match=(ct.new &&
> ip4.dst == 172.16.0.10 && ct_tcp.dst == 80), action=(reg4 = 172.16.0.10;
> reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
> >     table=??(ls_in_lb           ), priority=150  , match=(reg9[[6]] == 1
> && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg2[[0..15]]
> == 80), action=(reg4 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=
> 10.0.0.2:80);)
> >     table=??(ls_in_lb           ), priority=150  , match=(reg9[[6]] == 1
> && ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg2[[0..15]]
> == 80), action=(reg4 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=
> 20.0.0.2:80);)
>
>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to