On Thu, Nov 7, 2024 at 8:02 AM Dumitru Ceara <[email protected]> wrote:
>
> Hi Numan,
>
> Thanks for the fix!
>
> On 11/5/24 18:00, [email protected] wrote:
> > From: Numan Siddique <[email protected]>
> >
> > If we have a UDP load balancer - 10.0.0.10:80 = 10.0.0.3:8080, in order to
> > determine if the load balanced traffic needs to be hairpinned, the
> > vip - 10.0.0.10 and the vip port - 80 are stored in the registers before
> > the packet is load balanced using the below logical flow -
> >
> > table=6 (ls_in_pre_stateful ), priority=120 ,
> > match=(reg0[2] == 1 && ip4.dst == 10.0.0.10 && tcp.dst == 80),
> > action=(reg1 = 10.0.0.10; reg2[0..15] = 80; ct_lb_mark;)
> >
> > These registers are used in the later stages to check if the load balanced
> > packet needs to be hairpinned or not.
> >
> > However, if the packet is fragmented we may not be able to match on the
> > L4 fields (tcp, udp or sctp dest port) and this breaks the hairpin
> > traffic.
> >
> > This patch addressed this issue by making use of ct_nw_dst/ct_ip6_dst and
> > ct_tp_dst conntrack fields to determine the hairpin load balanced
> > traffic.
> >
>
> You mentioned it in the code comments but it's probably worth mentioning
> in the commit log too:
>
> Relying on conntrack to reassemble packets is not exactly correct, it
> only accidentaly works with the kernel datapath. In our internal bug
> tracking system we have this issue to track this incorrect assumption:
>
> https://issues.redhat.com/browse/FDP-913
>
> > In order to not break hardware offload on certain smart nics, care is taken
> > to match on these fields only for fragmented packets.
> >
> > Reported-at: https://issues.redhat.com/browse/FDP-905
> > Fixes: 1139b655c996 ("Don't blindly save original dst IP and Port to avoid
> > megaflow unwildcarding.")
> > CC: Han Zhou <[email protected]>
> > Suggested-by: Dumitru Ceara <[email protected]>
> > Signed-off-by: Numan Siddique <[email protected]>
> > ---
> > controller/lflow.c | 3 +
> > controller/lflow.h | 4 +
> > controller/physical.c | 37 +++++++++
> > include/ovn/actions.h | 14 +++-
> > include/ovn/logical-fields.h | 4 +
> > lib/actions.c | 138 ++++++++++++++++++++++++++++----
> > northd/northd.c | 57 +++++++++++++-
> > ovn-sb.xml | 27 +++++++
> > tests/ovn-macros.at | 3 +
> > tests/ovn-northd.at | 70 +++++++++-------
> > tests/ovn.at | 56 ++++++++++++-
> > tests/system-ovn-kmod.at | 149 +++++++++++++++++++++++++++++++++++
> > tests/test-ovn.c | 3 +
> > utilities/ovn-trace.c | 6 ++
> > 14 files changed, 520 insertions(+), 51 deletions(-)
> >
> > diff --git a/controller/lflow.c b/controller/lflow.c
> > index 13c3a0d73e..76b4952fd4 100644
> > --- a/controller/lflow.c
> > +++ b/controller/lflow.c
> > @@ -886,6 +886,9 @@ add_matches_to_flow_table(const struct
> > sbrec_logical_flow *lflow,
> > .in_port_sec_ptable = OFTABLE_CHK_IN_PORT_SEC,
> > .out_port_sec_ptable = OFTABLE_CHK_OUT_PORT_SEC,
> > .mac_cache_use_table = OFTABLE_MAC_CACHE_USE,
> > + .ct_nw_dst_load_table = OFTABLE_CT_ORIG_NW_DST_LOAD,
> > + .ct_ip6_dst_load_table = OFTABLE_CT_ORIG_IP6_DST_LOAD,
> > + .ct_tp_dst_load_table = OFTABLE_CT_ORIG_TP_DST_LOAD,
> > .ctrl_meter_id = ctrl_meter_id,
> > .common_nat_ct_zone = get_common_nat_zone(ldp),
> > };
> > diff --git a/controller/lflow.h b/controller/lflow.h
> > index e95a016501..58a12ee0fe 100644
> > --- a/controller/lflow.h
> > +++ b/controller/lflow.h
> > @@ -95,6 +95,10 @@ struct uuid;
> > #define OFTABLE_CHK_LB_AFFINITY 78
> > #define OFTABLE_MAC_CACHE_USE 79
> > #define OFTABLE_CT_ZONE_LOOKUP 80
> > +#define OFTABLE_CT_ORIG_NW_DST_LOAD 81
> > +#define OFTABLE_CT_ORIG_IP6_DST_LOAD 82
> > +#define OFTABLE_CT_ORIG_TP_DST_LOAD 83
> > +
> >
> > struct lflow_ctx_in {
> > struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath;
> > diff --git a/controller/physical.c b/controller/physical.c
> > index 2aaa16cbd0..855936ba4e 100644
> > --- a/controller/physical.c
> > +++ b/controller/physical.c
> > @@ -2770,5 +2770,42 @@ 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.dnat 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_DST_NAT;
>
> I did some testing with this patch and these flows are actually only hit
> if the ct_state of the session is +est - that's fine.
>
> However, because ovn-northd generates flows that resubmit all IP
> fragments to these tables in the "in_lb" stage of the pipeline, before
> we could decide if this is part of a hairpin session or not (that
> happens later in "in_pre_hairpin"), it means that all IP fragments that
> are part of load balanced sessions will match on ct_state=+trk+dnat in
> the datapath - including those on sessions that are not hairpin.
>
> As you mentioned off-list yesterday, that breaks HW offload on certain
> hardware for fragmented load balanced traffic:
> https://github.com/ovn-org/ovn/commit/110e670
>
> I experimented a bit and it seems to me that we can just avoid the
> ct_state=+trk+dnat match all toghether.
>
> I changed this to +trk+est (established is a prerequisite for ct_nw/tp_*
> fields):
>
> uint32_t ct_state = OVS_CS_F_TRACKED | OVS_CS_F_ESTABLISHED;
>
> and traffic seems to be natted properly for hairpin sessions with
> fragmented traffic too.
Hi Dumitru,
Thanks for review comments and for the suggestion. This works.
I've addressed your comments and submitted v2.
Please take a look.
Numan
>
> > + match_init_catchall(&match);
> > + ofpbuf_clear(&ofpacts);
> > +
> > + /* Add the flow:
> > + * match = (ct.trk && ct.dnat), action = (reg8 = ct_tp_dst)
> > + * table = 83
> > + */
> > + match_set_ct_state_masked(&match, ct_state, ct_state);
> > + 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 = (ct.trk && ct.dnat && ip4), action = (reg4 = ct_nw_dst)
> > + * table = 81
> > + */
> > + ofpbuf_clear(&ofpacts);
> > + match_set_dl_type(&match, 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,
> > + &ofpacts, hc_uuid);
> > +
> > + /* Add the flow:
> > + * match = (ct.trk && ct.dnat && ip6), action = (xxreg0 = ct_ip6_dst)
> > + * table = 82
> > + */
> > + ofpbuf_clear(&ofpacts);
> > + match_set_dl_type(&match, 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,
> > + &ofpacts, hc_uuid);
> > +
> > ofpbuf_uninit(&ofpacts);
> > }
> > diff --git a/include/ovn/actions.h b/include/ovn/actions.h
> > index 63a12a8821..91a6139b00 100644
> > --- a/include/ovn/actions.h
> > +++ b/include/ovn/actions.h
> > @@ -131,6 +131,9 @@ struct collector_set_ids;
> > OVNACT(CHK_LB_AFF, ovnact_result) \
> > OVNACT(SAMPLE, ovnact_sample) \
> > OVNACT(MAC_CACHE_USE, ovnact_null) \
> > + OVNACT(CT_ORIG_NW_DST, ovnact_result) \
> > + OVNACT(CT_ORIG_IP6_DST, ovnact_result) \
> > + OVNACT(CT_ORIG_TP_DST, ovnact_result) \
> >
> > /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
> > enum OVS_PACKED_ENUM ovnact_type {
> > @@ -416,10 +419,11 @@ struct ovnact_set_queue {
> > uint16_t queue_id;
> > };
> >
> > -/* OVNACT_DNS_LOOKUP, OVNACT_CHK_LB_HAIRPIN, OVNACT_CHK_LB_HAIRPIN_REPLY.
> > */
> > +/* OVNACT_DNS_LOOKUP, OVNACT_CHK_LB_HAIRPIN, OVNACT_CHK_LB_HAIRPIN_REPLY,
> > + * OVNACT_CT_ORIG_NW_DST, CT_ORIG_IP6_DST, CT_ORIG_TP_DST */
> > struct ovnact_result {
> > struct ovnact ovnact;
> > - struct expr_field dst; /* 1-bit destination field. */
> > + struct expr_field dst; /* destination field. */
> > };
> >
> > /* OVNACT_LOG. */
> > @@ -935,6 +939,12 @@ struct ovnact_encode_params {
> > this determines which CT zone to use */
> > uint32_t mac_cache_use_table; /* OpenFlow table for 'mac_cache_use'
> > * to resubmit. */
> > + uint32_t ct_nw_dst_load_table; /* OpenFlow table for 'ct_nw_dst'
> > + * to resubmit. */
> > + uint32_t ct_ip6_dst_load_table; /* OpenFlow table for 'ct_ip6_dst'
> > + * to resubmit. */
> > + uint32_t ct_tp_dst_load_table; /* OpenFlow table for 'ct_tp_dst'
> > + * to resubmit. */
> > };
> >
> > void ovnacts_encode(const struct ovnact[], size_t ovnacts_len,
> > diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
> > index d6c4a9b6b3..d563e044cb 100644
> > --- a/include/ovn/logical-fields.h
> > +++ b/include/ovn/logical-fields.h
> > @@ -60,6 +60,10 @@ enum ovn_controller_event {
> > #define MFF_LOG_LB_AFF_MATCH_LR_IP6_ADDR MFF_XXREG1
> > #define MFF_LOG_LB_AFF_MATCH_PORT MFF_REG8
> >
> > +#define MFF_LOG_CT_ORIG_NW_DST_ADDR MFF_REG4
> > +#define MFF_LOG_CT_ORIG_IP6_DST_ADDR MFF_XXREG0
> > +#define MFF_LOG_CT_ORIG_TP_DST_PORT MFF_REG8
> > +
> > void ovn_init_symtab(struct shash *symtab);
> >
> > /* MFF_LOG_FLAGS_REG bit assignments */
> > diff --git a/lib/actions.c b/lib/actions.c
> > index c5bde996b7..d5fc30b27a 100644
> > --- a/lib/actions.c
> > +++ b/lib/actions.c
> > @@ -3280,9 +3280,10 @@ ovnact_set_queue_free(struct ovnact_set_queue *a
> > OVS_UNUSED)
> > }
> >
> > static void
> > -parse_ovnact_result(struct action_context *ctx, const char *name,
> > - const char *prereq, const struct expr_field *dst,
> > - struct ovnact_result *res)
> > +parse_ovnact_result__(struct action_context *ctx, const char *name,
> > + const char *prereq, const struct expr_field *dst,
> > + struct ovnact_result *res,
> > + int n_bits)
> > {
> > lexer_get(ctx->lexer); /* Skip action name. */
> > lexer_get(ctx->lexer); /* Skip '('. */
> > @@ -3290,8 +3291,8 @@ parse_ovnact_result(struct action_context *ctx, const
> > char *name,
> > lexer_error(ctx->lexer, "%s doesn't take any parameters", name);
> > return;
> > }
> > - /* Validate that the destination is a 1-bit, modifiable field. */
> > - char *error = expr_type_check(dst, 1, true, ctx->scope);
> > + /* Validate that the destination is n_bits, modifiable field. */
> > + char *error = expr_type_check(dst, n_bits, true, ctx->scope);
> > if (error) {
> > lexer_error(ctx->lexer, "%s", error);
> > free(error);
> > @@ -3304,6 +3305,14 @@ parse_ovnact_result(struct action_context *ctx,
> > const char *name,
> > }
> > }
> >
> > +static void
> > +parse_ovnact_result(struct action_context *ctx, const char *name,
> > + const char *prereq, const struct expr_field *dst,
> > + struct ovnact_result *res)
> > +{
> > + parse_ovnact_result__(ctx, name, prereq, dst, res, 1);
> > +}
> > +
> > static void
> > parse_dns_lookup(struct action_context *ctx, const struct expr_field *dst,
> > struct ovnact_result *dl)
> > @@ -4299,22 +4308,40 @@ format_CHK_LB_HAIRPIN_REPLY(const struct
> > ovnact_result *res, struct ds *s)
> > ds_put_cstr(s, " = chk_lb_hairpin_reply();");
> > }
> >
> > +static void
> > +encode_result_action___(const struct ovnact_result *res,
> > + uint8_t resubmit_table,
> > + enum mf_field_id dst,
> > + int ofs, int n_bits,
> > + struct ofpbuf *ofpacts)
> > +{
> > + ovs_assert(n_bits <= 128);
> > +
> > + struct mf_subfield res_dst = expr_resolve_field(&res->dst);
> > + ovs_assert(res_dst.field);
> > +
> > + put_load(0, dst, ofs, n_bits < 64 ? n_bits : 64, ofpacts);
> > + if (n_bits > 64) {
> > + put_load(0, dst, ofs + 64, n_bits - 64, ofpacts);
> > + }
> > +
> > + emit_resubmit(ofpacts, resubmit_table);
> > +
> > + struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts);
> > + orm->dst = res_dst;
> > + orm->src.field = mf_from_id(dst);
> > + orm->src.ofs = ofs;
> > + orm->src.n_bits = n_bits;
> > +}
> > +
> > static void
> > encode_result_action__(const struct ovnact_result *res,
> > uint8_t resubmit_table,
> > int log_flags_result_bit,
> > struct ofpbuf *ofpacts)
> > {
> > - struct mf_subfield dst = expr_resolve_field(&res->dst);
> > - ovs_assert(dst.field);
> > - put_load(0, MFF_LOG_FLAGS, log_flags_result_bit, 1, ofpacts);
> > - emit_resubmit(ofpacts, resubmit_table);
> > -
> > - struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts);
> > - orm->dst = dst;
> > - orm->src.field = mf_from_id(MFF_LOG_FLAGS);
> > - orm->src.ofs = log_flags_result_bit;
> > - orm->src.n_bits = 1;
> > + encode_result_action___(res, resubmit_table, MFF_LOG_FLAGS,
> > + log_flags_result_bit, 1, ofpacts);
> > }
> >
> > static void
> > @@ -5435,6 +5462,75 @@ encode_MAC_CACHE_USE(const struct ovnact_null *null
> > OVS_UNUSED,
> > emit_resubmit(ofpacts, ep->mac_cache_use_table);
> > }
> >
> > +static void
> > +encode_CT_ORIG_NW_DST(const struct ovnact_result *res,
> > + const struct ovnact_encode_params *ep,
> > + struct ofpbuf *ofpacts)
> > +{
> > + encode_result_action___(res, ep->ct_nw_dst_load_table,
> > + MFF_LOG_CT_ORIG_NW_DST_ADDR, 0, 32, ofpacts);
> > +}
> > +
> > +static void
> > +parse_CT_ORIG_NW_DST(struct action_context *ctx, const struct expr_field
> > *dst,
> > + struct ovnact_result *res)
> > +{
> > + parse_ovnact_result__(ctx, "ct_nw_dst", NULL, dst, res, 32);
> > +}
> > +
> > +static void
> > +format_CT_ORIG_NW_DST(const struct ovnact_result *res, struct ds *s)
> > +{
> > + expr_field_format(&res->dst, s);
> > + ds_put_cstr(s, " = ct_nw_dst();");
> > +}
> > +
> > +static void
> > +encode_CT_ORIG_IP6_DST(const struct ovnact_result *res,
> > + const struct ovnact_encode_params *ep,
> > + struct ofpbuf *ofpacts)
> > +{
> > + encode_result_action___(res, ep->ct_ip6_dst_load_table,
> > + MFF_LOG_CT_ORIG_IP6_DST_ADDR, 0, 128, ofpacts);
> > +}
> > +
> > +static void
> > +parse_CT_ORIG_IP6_DST(struct action_context *ctx, const struct expr_field
> > *dst,
> > + struct ovnact_result *res)
> > +{
> > + parse_ovnact_result__(ctx, "ct_ip6_dst", NULL, dst, res, 128);
> > +}
> > +
> > +static void
> > +format_CT_ORIG_IP6_DST(const struct ovnact_result *res, struct ds *s)
> > +{
> > + expr_field_format(&res->dst, s);
> > + ds_put_cstr(s, " = ct_ip6_dst();");
> > +}
> > +
> > +static void
> > +encode_CT_ORIG_TP_DST(const struct ovnact_result *res,
> > + const struct ovnact_encode_params *ep OVS_UNUSED,
> > + struct ofpbuf *ofpacts)
> > +{
> > + encode_result_action___(res, ep->ct_tp_dst_load_table,
> > + MFF_LOG_CT_ORIG_TP_DST_PORT, 0, 16, ofpacts);
> > +}
> > +
> > +static void
> > +parse_CT_ORIG_TP_DST(struct action_context *ctx, const struct expr_field
> > *dst,
> > + struct ovnact_result *res)
> > +{
> > + parse_ovnact_result__(ctx, "ct_tp_dst", NULL, dst, res, 16);
> > +}
> > +
> > +static void
> > +format_CT_ORIG_TP_DST(const struct ovnact_result *res, struct ds *s)
> > +{
> > + expr_field_format(&res->dst, s);
> > + ds_put_cstr(s, " = ct_tp_dst();");
> > +}
> > +
> > /* Parses an assignment or exchange or put_dhcp_opts action. */
> > static void
> > parse_set_action(struct action_context *ctx)
> > @@ -5529,6 +5625,18 @@ parse_set_action(struct action_context *ctx)
> > } else if (lexer_match_id(ctx->lexer, "dhcp_relay_resp_chk")) {
> > parse_dhcp_relay_chk(
> > ctx, &lhs, ovnact_put_DHCPV4_RELAY_RESP_CHK(ctx->ovnacts));
> > + } else if (!strcmp(ctx->lexer->token.s, "ct_nw_dst") &&
> > + lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
> > + parse_CT_ORIG_NW_DST(ctx, &lhs,
> > + ovnact_put_CT_ORIG_NW_DST(ctx->ovnacts));
> > + } else if (!strcmp(ctx->lexer->token.s, "ct_ip6_dst") &&
> > + lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
> > + parse_CT_ORIG_IP6_DST(ctx, &lhs,
> > +
> > ovnact_put_CT_ORIG_IP6_DST(ctx->ovnacts));
> > + } else if (!strcmp(ctx->lexer->token.s, "ct_tp_dst") &&
> > + lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
> > + parse_CT_ORIG_TP_DST(ctx, &lhs,
> > + ovnact_put_CT_ORIG_TP_DST(ctx->ovnacts));
> > } else {
> > parse_assignment_action(ctx, false, &lhs);
> > }
> > diff --git a/northd/northd.c b/northd/northd.c
> > index 3037ce0b55..985283a98e 100644
> > --- a/northd/northd.c
> > +++ b/northd/northd.c
> > @@ -124,6 +124,7 @@ static bool vxlan_mode;
> > #define REGBIT_ACL_STATELESS "reg0[16]"
> > #define REGBIT_ACL_HINT_ALLOW_REL "reg0[17]"
> > #define REGBIT_FROM_ROUTER_PORT "reg0[18]"
> > +#define REGBIT_IP_FRAG "reg0[19]"
> >
> > #define REG_ORIG_DIP_IPV4 "reg1"
> > #define REG_ORIG_DIP_IPV6 "xxreg1"
> > @@ -6398,6 +6399,13 @@ build_pre_stateful(struct ovn_datapath *od,
> >
> > /* Note: priority-120 flows are added in
> > build_lb_rules_pre_stateful(). */
> >
> > + /* If the packet is fragmented, set the REGBIT_IP_FRAG reg bit to 1
> > + * as ip.is_frag will not be preserved after conntrack recirculation.
> > */
> > + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 115,
> > + REGBIT_CONNTRACK_NAT" == 1 && ip.is_frag",
> > + REGBIT_IP_FRAG" = 1; ct_lb_mark;",
> > + lflow_ref);
> > +
> > ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 110,
> > REGBIT_CONNTRACK_NAT" == 1", "ct_lb_mark;",
> > lflow_ref);
> > @@ -8240,13 +8248,32 @@ build_lb_rules(struct lflow_table *lflows, struct
> > ovn_lb_datapaths *lb_dps,
> > struct ovn_lb_vip *lb_vip = &lb->vips[i];
> > struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[i];
> > const char *ip_match = NULL;
> > +
> > + ds_clear(action);
> > +
> > + /* Store the original destination IP to be used when generating
> > + * hairpin flows.
> > + * If the packet is fragmented, then the flow which saves the
> > + * original destination IP (and port) in the "ls_in_pre_stateful"
> > + * stage will not be hit.
> > + */
> > if (lb_vip->address_family == AF_INET) {
> > ip_match = "ip4";
> > + ds_put_format(action, REG_ORIG_DIP_IPV4 " = %s; ",
> > + lb_vip->vip_str);
> > } else {
> > ip_match = "ip6";
> > + ds_put_format(action, REG_ORIG_DIP_IPV6 " = %s; ",
> > + lb_vip->vip_str);
> > }
> >
> > - ds_clear(action);
> > + if (lb_vip->port_str) {
> > + /* Store the original destination port to be used when
> > generating
> > + * hairpin flows.
> > + */
> > + ds_put_format(action, REG_ORIG_TP_DPORT " = %s; ",
> > + lb_vip->port_str);
> > + }
> > ds_clear(match);
> >
> > /* New connections in Ingress table. */
> > @@ -8378,8 +8405,32 @@ build_lb_hairpin(const struct ls_stateful_record
> > *ls_stateful_rec,
> > lflow_ref);
> >
> > if (ls_stateful_rec->has_lb_vip) {
> > - /* Check if the packet needs to be hairpinned.
> > - * Set REGBIT_HAIRPIN in the original direction and
> > + /* Check if the packet needs to be hairpinned. */
> > +
> > + /* In order to check if the fragmented packets needs to be
> > + * hairpinned we need to save the ct tuple original IPv4/v6
> > + * destination and L4 destination port in the registers after
> > + * the conntrack recirculation.
> > + *
> > + * Note: We are assuming that sending the packets to conntrack
> > + * will reassemble the packet and L4 fields will be available.
> > + * It is a risky assumption as ovs-vswitchd doesn't guarantee it
> > + * and userspace datapath doesn't reassemble the fragmented packets
> > + * after conntrack. It is the kernel datapath conntrack behavior.
> > + * 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",
>
> Why do we do this only for packets in the original direction. Don't we
> need to be able to detect hairpin on replies too? I removed the !ct.rpl
> condition and things seem to work fine.
>
> > + REG_ORIG_DIP_IPV4 " = ct_nw_dst(); "
> > + REG_ORIG_TP_DPORT " = 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",
> > + REG_ORIG_DIP_IPV6 " = ct_ip6_dst(); "
> > + REG_ORIG_TP_DPORT " = ct_tp_dst(); next;",
> > + lflow_ref);
> > +
> > + /* Set REGBIT_HAIRPIN in the original direction and
> > * REGBIT_HAIRPIN_REPLY in the reply direction.
> > */
> > ovn_lflow_add_with_hint(
> > diff --git a/ovn-sb.xml b/ovn-sb.xml
> > index 479d3e2851..ea4adc1c34 100644
> > --- a/ovn-sb.xml
> > +++ b/ovn-sb.xml
> > @@ -2766,6 +2766,33 @@ tcp.flags = RST;
> > </p>
> > </dd>
> >
> > + <dt><code><var>R</var> = ct_nw_dst();</code></dt>
> > + <dd>
> > + <p>
> > + This action checks if the packet is tracked and stores the
> > + conntrack original destination IPv4 address in the register
> > + <var>R</var> of 32-bit size.
> > + </p>
> > + </dd>
> > +
> > + <dt><code><var>R</var> = ct_ip6_dst();</code></dt>
> > + <dd>
> > + <p>
> > + This action checks if the packet is tracked and stores the
> > + conntrack original destination IPv6 address in the register
> > + <var>R</var> of 128-bit size.
> > + </p>
> > + </dd>
> > +
> > + <dt><code><var>R</var> = ct_tp_dst();</code></dt>
> > + <dd>
> > + <p>
> > + This action checks if the packet is tracked and stores the
> > + conntrack original L4 destination port in the register
> > + <var>R</var> of 16-bit size.
> > + </p>
> > + </dd>
> > +
> > <dt><code>sample(probability=<var>packets</var>, ...)</code></dt>
> > <dd>
> > <p>
> > diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at
> > index 77d1515f6f..a88556aa99 100644
> > --- a/tests/ovn-macros.at
> > +++ b/tests/ovn-macros.at
> > @@ -1217,5 +1217,8 @@ m4_define([OFTABLE_ECMP_NH], [77])
> > m4_define([OFTABLE_CHK_LB_AFFINITY], [78])
> > m4_define([OFTABLE_MAC_CACHE_USE], [79])
> > m4_define([OFTABLE_CT_ZONE_LOOKUP], [80])
> > +m4_define([OFTABLE_CT_ORIG_NW_DST_LOAD], [81])
> > +m4_define([OFTABLE_CT_ORIG_IP6_DST_LOAD], [82])
> > +m4_define([OFTABLE_CT_ORIG_TP_DST_LOAD], [83])
> >
> > m4_define([OFTABLE_SAVE_INPORT_HEX], [m4_eval(OFTABLE_SAVE_INPORT, 16)])
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index d1f7f105c0..e1386323a7 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -1415,7 +1415,7 @@ check ovn-nbctl --wait=sb ls-lb-add sw0 lb1
> > AT_CAPTURE_FILE([sbflows])
> > OVS_WAIT_FOR_OUTPUT(
> > [ovn-sbctl dump-flows sw0 | tee sbflows | grep 'priority=120.*backends'
> > | ovn_strip_lflows], 0, [dnl
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80),
> > action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > ])
> >
> > # disabled LSPs should not be a backend of Load Balancer
> > @@ -1424,7 +1424,7 @@ check ovn-nbctl lsp-set-enabled sw0-p1 disabled
> > AT_CAPTURE_FILE([sbflows])
> > OVS_WAIT_FOR_OUTPUT(
> > [ovn-sbctl dump-flows sw0 | tee sbflows | grep 'priority=120.*backends'
> > | ovn_strip_lflows], 0, [dnl
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(ct_lb_mark(backends=20.0.0.3:80);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=20.0.0.3:80);)
> > ])
> > wait_row_count Service_Monitor 1
> >
> > @@ -1433,7 +1433,7 @@ check ovn-nbctl lsp-set-enabled sw0-p1 enabled
> > AT_CAPTURE_FILE([sbflows])
> > OVS_WAIT_FOR_OUTPUT(
> > [ovn-sbctl dump-flows sw0 | tee sbflows | grep 'priority=120.*backends'
> > | ovn_strip_lflows], 0, [dnl
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80),
> > action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > ])
> > wait_row_count Service_Monitor 2
> >
> > @@ -1444,7 +1444,7 @@ wait_row_count Service_Monitor 0
> > AT_CAPTURE_FILE([sbflows2])
> > OVS_WAIT_FOR_OUTPUT(
> > [ovn-sbctl dump-flows sw0 | tee sbflows2 | grep 'priority=120.*backends'
> > | ovn_strip_lflows], [0],
> > -[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80),
> > action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > +[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > ])
> >
> > AS_BOX([Create the Load_Balancer_Health_Check again.])
> > @@ -1456,7 +1456,7 @@ check ovn-nbctl --wait=sb sync
> >
> > ovn-sbctl dump-flows sw0 | grep backends | grep priority=120 > lflows.txt
> > AT_CHECK([cat lflows.txt | ovn_strip_lflows], [0], [dnl
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80),
> > action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > ])
> >
> > AS_BOX([Get the uuid of both the service_monitor])
> > @@ -1466,7 +1466,7 @@ sm_sw1_p1=$(fetch_column Service_Monitor _uuid
> > logical_port=sw1-p1)
> > AT_CAPTURE_FILE([sbflows3])
> > OVS_WAIT_FOR_OUTPUT(
> > [ovn-sbctl dump-flows sw0 | tee sbflows 3 | grep
> > 'priority=120.*backends' | ovn_strip_lflows], [0],
> > -[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80),
> > action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > +[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > ])
> >
> > AS_BOX([Set the service monitor for sw1-p1 to offline])
> > @@ -1477,7 +1477,7 @@ check ovn-nbctl --wait=sb sync
> > AT_CAPTURE_FILE([sbflows4])
> > OVS_WAIT_FOR_OUTPUT(
> > [ovn-sbctl dump-flows sw0 | tee sbflows4 | grep 'priority=120.*backends'
> > | ovn_strip_lflows], [0],
> > -[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.3:80);)
> > +[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.3:80);)
> > ])
> >
> > AS_BOX([Set the service monitor for sw0-p1 to offline])
> > @@ -1506,7 +1506,7 @@ check ovn-nbctl --wait=sb sync
> > AT_CAPTURE_FILE([sbflows7])
> > OVS_WAIT_FOR_OUTPUT(
> > [ovn-sbctl dump-flows sw0 | tee sbflows7 | grep backends | grep
> > priority=120 | ovn_strip_lflows], 0,
> > -[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80),
> > action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > +[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > ])
> >
> > AS_BOX([Set the service monitor for sw1-p1 to error])
> > @@ -1517,7 +1517,7 @@ check ovn-nbctl --wait=sb sync
> > ovn-sbctl dump-flows sw0 | grep "ip4.dst == 10.0.0.10 && tcp.dst == 80" \
> > | grep priority=120 > lflows.txt
> > AT_CHECK([cat lflows.txt | grep ls_in_lb | ovn_strip_lflows], [0], [dnl
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.3:80);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.3:80);)
> > ])
> >
> > AS_BOX([Add one more vip to lb1])
> > @@ -1543,8 +1543,8 @@ AT_CAPTURE_FILE([sbflows9])
> > OVS_WAIT_FOR_OUTPUT(
> > [ovn-sbctl dump-flows sw0 | tee sbflows9 | grep backends | grep
> > priority=120 | ovn_strip_lflows],
> > 0,
> > -[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.3:80);)
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.40 && tcp.dst == 1000),
> > action=(ct_lb_mark(backends=10.0.0.3:1000);)
> > +[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.3:80);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.40 && tcp.dst == 1000), action=(reg1 = 10.0.0.40; reg2[[0..15]] =
> > 1000; ct_lb_mark(backends=10.0.0.3:1000);)
> > ])
> >
> > AS_BOX([Set the service monitor for sw1-p1 to online])
> > @@ -1557,8 +1557,8 @@ AT_CAPTURE_FILE([sbflows10])
> > OVS_WAIT_FOR_OUTPUT(
> > [ovn-sbctl dump-flows sw0 | tee sbflows10 | grep backends | grep
> > priority=120 | ovn_strip_lflows],
> > 0,
> > -[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80),
> > action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.40 && tcp.dst == 1000),
> > action=(ct_lb_mark(backends=10.0.0.3:1000,20.0.0.3:80);)
> > +[ table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.40 && tcp.dst == 1000), action=(reg1 = 10.0.0.40; reg2[[0..15]] =
> > 1000; ct_lb_mark(backends=10.0.0.3:1000,20.0.0.3:80);)
> > ])
> >
> > AS_BOX([Associate lb1 to sw1])
> > @@ -1567,8 +1567,8 @@ AT_CAPTURE_FILE([sbflows11])
> > OVS_WAIT_FOR_OUTPUT(
> > [ovn-sbctl dump-flows sw1 | tee sbflows11 | grep backends | grep
> > priority=120 | ovn_strip_lflows],
> > 0, [dnl
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80),
> > action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.40 && tcp.dst == 1000),
> > action=(ct_lb_mark(backends=10.0.0.3:1000,20.0.0.3:80);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.40 && tcp.dst == 1000), action=(reg1 = 10.0.0.40; reg2[[0..15]] =
> > 1000; ct_lb_mark(backends=10.0.0.3:1000,20.0.0.3:80);)
> > ])
> >
> > AS_BOX([Now create lb2 same as lb1 but udp protocol.])
> > @@ -4653,14 +4653,17 @@ check_stateful_flows() {
> > table=??(ls_in_pre_stateful ), priority=0 , match=(1), action=(next;)
> > table=??(ls_in_pre_stateful ), priority=100 , match=(reg0[[0]] == 1),
> > action=(ct_next;)
> > table=??(ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1),
> > action=(ct_lb_mark;)
> > + table=??(ls_in_pre_stateful ), priority=115 , match=(reg0[[2]] == 1 &&
> > ip.is_frag), action=(reg0[[19]] = 1; ct_lb_mark;)
> > table=??(ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 &&
> > ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10;
> > reg2[[0..15]] = 80; ct_lb_mark;)
> > table=??(ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 &&
> > ip4.dst == 10.0.0.20 && tcp.dst == 80), action=(reg1 = 10.0.0.20;
> > reg2[[0..15]] = 80; ct_lb_mark;)
> > ])
> >
> > 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=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);)
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 10.0.0.20 && tcp.dst == 80),
> > action=(ct_lb_mark(backends=10.0.0.40:8080);)
> > + table=??(ls_in_lb ), priority=110 , match=(ct.trk && !ct.rpl
> > && reg0[[19]] == 1 && ip4), action=(reg1 = 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=120 , match=(ct.new && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 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 && tcp.dst == 80), action=(reg1 = 10.0.0.20; reg2[[0..15]] =
> > 80; ct_lb_mark(backends=10.0.0.40:8080);)
> > ])
> >
> > AT_CHECK([grep "ls_in_stateful" sw0flows | ovn_strip_lflows], [0], [dnl
> > @@ -4724,6 +4727,7 @@ AT_CHECK([grep "ls_in_pre_stateful" sw0flows |
> > ovn_strip_lflows], [0], [dnl
> > table=??(ls_in_pre_stateful ), priority=0 , match=(1), action=(next;)
> > table=??(ls_in_pre_stateful ), priority=100 , match=(reg0[[0]] == 1),
> > action=(ct_next;)
> > table=??(ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1),
> > action=(ct_lb_mark;)
> > + table=??(ls_in_pre_stateful ), priority=115 , match=(reg0[[2]] == 1 &&
> > ip.is_frag), action=(reg0[[19]] = 1; ct_lb_mark;)
> > ])
> >
> > AT_CHECK([grep "ls_in_lb " sw0flows | ovn_strip_lflows], [0], [dnl
> > @@ -4764,6 +4768,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=(reg1 = 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;)
> > ])
> >
> > AT_CLEANUP
> > @@ -7763,7 +7769,9 @@ 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=(ct_lb_mark(backends=10.0.0.10);)
> > + table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst
> > == 10.0.0.2), action=(reg1 = 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=(reg1 = 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;)
> > ])
> >
> > AT_CHECK([grep -e "ls_in_stateful" lsflows | ovn_strip_lflows], [0], [dnl
> > @@ -7818,7 +7826,9 @@ 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=(ct_lb_mark(backends=10.0.0.10);)
> > + table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst
> > == 10.0.0.2), action=(reg1 = 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=(reg1 = 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;)
> > ])
> >
> > AT_CHECK([grep -e "ls_in_stateful" lsflows | ovn_strip_lflows], [0], [dnl
> > @@ -7873,7 +7883,9 @@ 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=(ct_lb_mark(backends=10.0.0.10);)
> > + table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst
> > == 10.0.0.2), action=(reg1 = 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=(reg1 = 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;)
> > ])
> >
> > AT_CHECK([grep -e "ls_in_stateful" lsflows | ovn_strip_lflows], [0], [dnl
> > @@ -9258,13 +9270,13 @@ AT_CAPTURE_FILE([S1flows])
> >
> > 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=120 , match=(ct.new && ip4.dst
> > == 172.16.0.10 && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.2:80);)
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 172.16.0.11 && tcp.dst == 8080),
> > action=(ct_lb_mark(backends=10.0.0.2:8080);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 172.16.0.10 && tcp.dst == 80), action=(reg1 = 172.16.0.10; reg2[[0..15]]
> > = 80; ct_lb_mark(backends=10.0.0.2:80);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 172.16.0.11 && tcp.dst == 8080), action=(reg1 = 172.16.0.11;
> > reg2[[0..15]] = 8080; ct_lb_mark(backends=10.0.0.2:8080);)
> > ])
> > AT_CHECK([grep "ls_in_lb " S1flows | ovn_strip_lflows], [0], [dnl
> > table=??(ls_in_lb ), priority=0 , match=(1), action=(next;)
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 172.16.0.10 && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.2:80);)
> > - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 172.16.0.11 && tcp.dst == 8080),
> > action=(ct_lb_mark(backends=10.0.0.2:8080);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 172.16.0.10 && tcp.dst == 80), action=(reg1 = 172.16.0.10; reg2[[0..15]]
> > = 80; ct_lb_mark(backends=10.0.0.2:80);)
> > + table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst
> > == 172.16.0.11 && tcp.dst == 8080), action=(reg1 = 172.16.0.11;
> > reg2[[0..15]] = 8080; ct_lb_mark(backends=10.0.0.2:8080);)
> > ])
> >
> > ovn-sbctl get datapath S0 _uuid > dp_uuids
> > @@ -9394,7 +9406,9 @@ 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=120 , match=(ct.new && ip4.dst
> > == 172.16.0.10 && tcp.dst == 80),
> > action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
> > + table=??(ls_in_lb ), priority=110 , match=(ct.trk && !ct.rpl
> > && reg0[[19]] == 1 && ip4), action=(reg1 = 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=120 , match=(ct.new && ip4.dst
> > == 172.16.0.10 && tcp.dst == 80), action=(reg1 = 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 && reg8[[0..15]] ==
> > 80), action=(reg1 = 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 && reg8[[0..15]] ==
> > 80), action=(reg1 = 172.16.0.10; reg2[[0..15]] = 80;
> > ct_lb_mark(backends=20.0.0.2:80);)
> > ])
> > @@ -13976,7 +13990,7 @@ AT_CHECK([grep "ls_in_pre_stateful" s1flows |
> > ovn_strip_lflows | grep "30.0.0.1"
> > table=??(ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 &&
> > ip4.dst == 30.0.0.1), action=(reg1 = 30.0.0.1; ct_lb_mark;)
> > ])
> > AT_CHECK([grep "ls_in_lb" s1flows | ovn_strip_lflows | grep "30.0.0.1"],
> > [0], [dnl
> > - table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst
> > == 30.0.0.1),
> > action=(ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);)
> > + table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst
> > == 30.0.0.1), action=(reg1 = 30.0.0.1;
> > ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);)
> > ])
> >
> > # Associate load balancer to lr1 with DGP
> > @@ -14090,7 +14104,7 @@ AT_CHECK([grep "ls_in_pre_stateful" s1flows |
> > ovn_strip_lflows | grep "2001:db8:
> > table=??(ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 &&
> > ip6.dst == 2001:db8:cccc::1), action=(xxreg1 = 2001:db8:cccc::1;
> > ct_lb_mark;)
> > ])
> > AT_CHECK([grep "ls_in_lb" s1flows | ovn_strip_lflows | grep
> > "2001:db8:cccc::1"], [0], [dnl
> > - table=??(ls_in_lb ), priority=110 , match=(ct.new && ip6.dst
> > == 2001:db8:cccc::1),
> > action=(ct_lb_mark(backends=2001:db8:aaaa:3::103,2001:db8:aaaa:3::102,2001:db8:aaaa:3::101);)
> > + table=??(ls_in_lb ), priority=110 , match=(ct.new && ip6.dst
> > == 2001:db8:cccc::1), action=(xxreg1 = 2001:db8:cccc::1;
> > ct_lb_mark(backends=2001:db8:aaaa:3::103,2001:db8:aaaa:3::102,2001:db8:aaaa:3::101);)
> > ])
> >
> > # Associate load balancer to lr1 with DGP
> > @@ -14201,7 +14215,7 @@ AT_CHECK([grep "ls_in_pre_stateful" s1flows |
> > ovn_strip_lflows | grep "30.0.0.1"
> > table=??(ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 &&
> > ip4.dst == 30.0.0.1), action=(reg1 = 30.0.0.1; ct_lb_mark;)
> > ])
> > AT_CHECK([grep "ls_in_lb" s1flows | ovn_strip_lflows | grep "30.0.0.1"],
> > [0], [dnl
> > - table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst
> > == 30.0.0.1),
> > action=(ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);)
> > + table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst
> > == 30.0.0.1), action=(reg1 = 30.0.0.1;
> > ct_lb_mark(backends=172.16.0.103,172.16.0.102,172.16.0.101);)
> > ])
> >
> > # Associate load balancer to lr1 with DGP
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index 10cd7a79b9..af3133f868 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -2418,6 +2418,54 @@ sample(probability=10, obs_point=ct_label);
> > mac_cache_use;
> > encodes as resubmit(,OFTABLE_MAC_CACHE_USE)
> >
> > +# ct_nw_dst()
> > +reg1 = ct_nw_dst();
> > + encodes as
> > set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[64..95]]
> > +
> > +xreg1[[3..34]] = ct_nw_dst();
> > + encodes as
> > set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[3..34]]
> > +
> > +reg1[[3..34]] = ct_nw_dst();
> > + Cannot select bits 3 to 34 of 32-bit field reg1.
> > +
> > +reg1[[3..35]] = ct_nw_dst();
> > + Cannot select bits 3 to 35 of 32-bit field reg1.
> > +
> > +reg1[[1]] = ct_nw_dst();
> > + Cannot use 1-bit field reg1[[1..1]] where 32-bit field is required.
> > +
> > +ct_nw_dst;
> > + Syntax error at `ct_nw_dst' expecting action.
> > +
> > +ct_nw_dst();
> > + Syntax error at `ct_nw_dst' expecting action.
> > +
> > +# ct_ip6_dst()
> > +xxreg1 = ct_ip6_dst();
> > + encodes as
> > set_field:0/0xffffffffffffffff->xxreg0,set_field:0/0xffffffffffffffff0000000000000000->xxreg0,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG0[[]]->NXM_NX_XXREG1[[]]
> > +
> > +reg1 = ct_ip6_dst();
> > + Cannot use 32-bit field reg1[[0..31]] where 128-bit field is required.
> > +
> > +ct_ip6_dst;
> > + Syntax error at `ct_ip6_dst' expecting action.
> > +
> > +ct_ip6_dst();
> > + Syntax error at `ct_ip6_dst' expecting action.
> > +
> > +# ct_tp_dst()
> > +reg1[[0..15]] = ct_tp_dst();
> > + encodes as
> > set_field:0/0xffff->reg8,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG8[[0..15]]->NXM_NX_XXREG0[[64..79]]
> > +
> > +reg1 = ct_tp_dst();
> > + Cannot use 32-bit field reg1[[0..31]] where 16-bit field is required.
> > +
> > +ct_tp_dst;
> > + Syntax error at `ct_tp_dst' expecting action.
> > +
> > +ct_tp_dst();
> > + Syntax error at `ct_tp_dst' expecting action.
> > +
> > # Miscellaneous negative tests.
> > ;
> > Syntax error at `;'.
> > @@ -25632,7 +25680,7 @@ OVS_WAIT_FOR_OUTPUT(
> > ovn-sbctl dump-flows sw0 | grep ct_lb_mark | grep priority=120 | sed
> > 's/table=..//'], 0,
> > [dnl
> > (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4.dst
> > == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] =
> > 80; ct_lb_mark;)
> > - (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst ==
> > 10.0.0.10 && tcp.dst == 80),
> > action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80;
> > hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");)
> > + (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst ==
> > 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80;
> > ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80;
> > hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");)
> > ])
> >
> > AT_CAPTURE_FILE([sbflows2])
> > @@ -25831,7 +25879,7 @@ OVS_WAIT_FOR_OUTPUT(
> > ovn-sbctl dump-flows sw0 | grep ct_lb_mark | grep priority=120 | sed
> > 's/table=..//'], 0,
> > [dnl
> > (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6.dst
> > == 2001::a && tcp.dst == 80), action=(xxreg1 = 2001::a; reg2[[0..15]] = 80;
> > ct_lb_mark;)
> > - (ls_in_lb ), priority=120 , match=(ct.new && ip6.dst ==
> > 2001::a && tcp.dst == 80),
> > action=(ct_lb_mark(backends=[[2001::3]]:80,[[2002::3]]:80;
> > hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");)
> > + (ls_in_lb ), priority=120 , match=(ct.new && ip6.dst ==
> > 2001::a && tcp.dst == 80), action=(xxreg1 = 2001::a; reg2[[0..15]] = 80;
> > ct_lb_mark(backends=[[2001::3]]:80,[[2002::3]]:80;
> > hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");)
> > ])
> >
> > AT_CAPTURE_FILE([sbflows2])
> > @@ -35663,7 +35711,9 @@ check_default_flows() {
> > for table in $(grep -oP "table=\K\d*, " oflows | tr -d ',' | sort -n |
> > uniq); do
> > # Tables 68 and 70 are part of the chk_lb_hairpin and
> > ct_snat_to_vip actions
> > # respectively and it's OK if they don't have a default action.
> > - if test ${table} -eq 68 -o ${table} -eq 70; then
> > + # Tables 81, 82 and 83 are part of ct_nw_dst(), ct_ip6_dst() and
> > ct_tp_dst()
> > + # actions respectively and its OK for them to not have default
> > flows.
> > + if test ${table} -eq 68 -o ${table} -eq 70 -o ${table} -eq 81 -o
> > ${table} -eq 82 -o ${table} -eq 83; then
> > continue;
> > fi
> > AT_CHECK([grep -qe "table=$table.* priority=0\(,metadata=0x\w*\)\?
> > actions" oflows], [0], [ignore], [ignore], [echo "Table $table does not
> > contain a default action"])
> > diff --git a/tests/system-ovn-kmod.at b/tests/system-ovn-kmod.at
> > index 75ecdadebe..b17ec53f43 100644
> > --- a/tests/system-ovn-kmod.at
> > +++ b/tests/system-ovn-kmod.at
> > @@ -1027,3 +1027,152 @@ OVS_TRAFFIC_VSWITCHD_STOP(["
> > "])
> > AT_CLEANUP
> > ])
> > +
> > +OVN_FOR_EACH_NORTHD([
> > +AT_SETUP([Load Balancer LS hairpin IPv4 UDP - larger than MTU])
> > +AT_SKIP_IF([test $HAVE_NC = no])
> > +AT_SKIP_IF([test $HAVE_TCPDUMP = no])
>
> We don't use tcpdump in the test.
>
> > +AT_KEYWORDS([lb])
> > +
> > +ovn_start
> > +
> > +OVS_TRAFFIC_VSWITCHD_START()
> > +ADD_BR([br-int])
> > +
> > +# Set external-ids in br-int needed for ovn-controller
> > +ovs-vsctl \
> > + -- set Open_vSwitch . external-ids:system-id=hv1 \
> > + -- set Open_vSwitch .
> > external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> > + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> > + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> > + -- set bridge br-int fail-mode=secure
> > other-config:disable-in-band=true
> > +
> > +# Start ovn-controller
> > +start_daemon ovn-controller
> > +
> > +# Logical network:
> > +# One logical switch with IPv4 load balancers that hairpin the traffic.
> > +ovn-nbctl ls-add sw
>
> Please add "check" in all places where it's applicable.
>
> > +ovn-nbctl lsp-add sw lsp -- lsp-set-addresses lsp 00:00:00:00:00:01
> > +ovn-nbctl lb-add lb-ipv4-tcp 88.88.88.88:8080 42.42.42.1:4041 tcp
>
> We don't use this load balancer.
>
> > +ovn-nbctl lb-add lb-ipv4-udp 88.88.88.88:4040 42.42.42.1:2021 udp
> > +ovn-nbctl ls-lb-add sw lb-ipv4-tcp
> > +ovn-nbctl ls-lb-add sw lb-ipv4-udp
> > +
> > +ovn-nbctl lr-add rtr
> > +ovn-nbctl lrp-add rtr rtr-sw 00:00:00:00:01:00 42.42.42.254/24
> > +ovn-nbctl lsp-add sw sw-rtr \
> > + -- lsp-set-type sw-rtr router \
> > + -- lsp-set-addresses sw-rtr 00:00:00:00:01:00 \
> > + -- lsp-set-options sw-rtr router-port=rtr-sw
> > +
> > +ADD_NAMESPACES(lsp)
> > +ADD_VETH(lsp, lsp, br-int, "42.42.42.1/24", "00:00:00:00:00:01", \
> > + "42.42.42.254")
> > +
> > +ovn-nbctl --wait=hv -t 3 sync
> > +
>
> No timeout needed.
>
> > +yes 1 | head -n 10000 | tr '\n' ' ' | dd of=datafile bs=7373 count=1
> > +cat datafile datafile datafile datafile > frag_test.expected
> > +
>
> Maybe:
>
> dnl Generate a datafile that's 8KB long.
> printf %8s > datafile
>
> > +# Start IPv4 UDP server on lsp.
> > +NETNS_DAEMONIZE([lsp], [nc -l -u 42.42.42.1 2021 -o udp_frag_test.rcvd],
> > [lsp0_udp.pid])
> > +
> > +NS_CHECK_EXEC([lsp], [nc -u 88.88.88.88 4040 -p 20000 < datafile], [0],
> > [ignore], [ignore])
> > +NS_CHECK_EXEC([lsp], [nc -u 88.88.88.88 4040 -p 20000 < datafile], [0],
> > [ignore], [ignore])
> > +NS_CHECK_EXEC([lsp], [nc -u 88.88.88.88 4040 -p 20000 < datafile], [0],
> > [ignore], [ignore])
> > +NS_CHECK_EXEC([lsp], [nc -u 88.88.88.88 4040 -p 20000 < datafile], [0],
> > [ignore], [ignore])
> > +
>
> This doesn't reply to UDP packets so the session doesn't move to
> established.
>
> Maybe we can try something like:
>
> NETNS_DAEMONIZE([lsp], [nc -e /bin/cat -u -v -l -o udp_frag_test.rcvd
> 2021], [lsp-nc.pid])
> NS_CHECK_EXEC([lsp], [(cat datafile; sleep 10) | nc -u 88.88.88.88 4040])
>
> This will make the server echo the incoming data. It will also dump all
> session data (incoming and outgoing) so we need to change the
> frag_test.expected contents (duplicate them).
>
> I added the ugly sleep 10 to avoid the client closing the socket too
> early - the kernel would generate ICMP port unreachable for the replies
> in that case. Maybe that can be done in a nicer way though.
>
> > +AT_CHECK([cmp frag_test.expected udp_frag_test.rcvd], [0], [ignore],
> > [ignore])
> This could be:
> check cmp frag_test.expected udp_frag_test.rcvd
>
> Most of the system test comments above also apply to the IPv6 test below.
>
> > +
> > +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> > +
> > +as ovn-sb
> > +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> > +
> > +as ovn-nb
> > +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> > +
> > +as northd
> > +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> > +
> > +as
> > +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> > +/connection dropped.*/d"])
> > +AT_CLEANUP
> > +])
> > +
> > +OVN_FOR_EACH_NORTHD([
> > +AT_SETUP([Load Balancer LS hairpin IPv6 UDP - larger than MTU])
> > +AT_SKIP_IF([test $HAVE_NC = no])
> > +AT_KEYWORDS([lb])
> > +
> > +ovn_start
> > +
> > +OVS_TRAFFIC_VSWITCHD_START()
> > +ADD_BR([br-int])
> > +
> > +# Set external-ids in br-int needed for ovn-controller
> > +ovs-vsctl \
> > + -- set Open_vSwitch . external-ids:system-id=hv1 \
> > + -- set Open_vSwitch .
> > external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> > + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> > + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> > + -- set bridge br-int fail-mode=secure
> > other-config:disable-in-band=true
> > +
> > +# Start ovn-controller
> > +start_daemon ovn-controller
> > +
> > +# Logical network:
> > +# One logical switch with IPv6 load balancers that hairpin the traffic.
> > +ovn-nbctl ls-add sw
> > +ovn-nbctl lsp-add sw lsp -- lsp-set-addresses lsp 00:00:00:00:00:01
> > +ovn-nbctl lb-add lb-ipv6-tcp [[8800::0088]]:8080 [[4200::1]]:4041 tcp
> > +ovn-nbctl lb-add lb-ipv6-udp [[8800::0088]]:4040 [[4200::1]]:2021 udp
> > +ovn-nbctl ls-lb-add sw lb-ipv6-tcp
> > +ovn-nbctl ls-lb-add sw lb-ipv6-udp
> > +
> > +ovn-nbctl lr-add rtr
> > +ovn-nbctl lrp-add rtr rtr-sw 00:00:00:00:01:00 4200::00ff/64
> > +ovn-nbctl lsp-add sw sw-rtr \
> > + -- lsp-set-type sw-rtr router \
> > + -- lsp-set-addresses sw-rtr 00:00:00:00:01:00 \
> > + -- lsp-set-options sw-rtr router-port=rtr-sw
> > +
> > +ovn-nbctl --wait=hv sync
> > +
> > +ADD_NAMESPACES(lsp)
> > +ADD_VETH(lsp, lsp, br-int, "4200::1/64", "00:00:00:00:00:01",
> > "4200::00ff", "nodad")
> > +ovn-nbctl --wait=hv -t 3 sync
>
>
>
> > +
> > +yes 1 | head -n 10000 | tr '\n' ' ' | dd of=datafile bs=7373 count=1
> > +cat datafile datafile datafile datafile > frag_test.expected
> > +
> > +# Start IPv6 UDP server on lsp.
> > +NETNS_DAEMONIZE([lsp], [nc -l -u 4200::1 2021 -o udp_frag_test.rcvd],
> > [lsp0_udp.pid])
> > +
> > +yes 1 | head -n 10000 | tr '\n' ' ' | dd of=datafile bs=7373 count=1
> > +NS_CHECK_EXEC([lsp], [nc -6 -u 8800::0088 4040 -p 20001 < datafile], [0],
> > [ignore], [ignore])
> > +NS_CHECK_EXEC([lsp], [nc -6 -u 8800::0088 4040 -p 20001 < datafile], [0],
> > [ignore], [ignore])
> > +NS_CHECK_EXEC([lsp], [nc -6 -u 8800::0088 4040 -p 20001 < datafile], [0],
> > [ignore], [ignore])
> > +NS_CHECK_EXEC([lsp], [nc -6 -u 8800::0088 4040 -p 20001 < datafile], [0],
> > [ignore], [ignore])
> > +
> > +cat datafile datafile datafile datafile > udp_frag_test.expected
> > +AT_CHECK([cmp udp_frag_test.expected udp_frag_test.rcvd], [0], [ignore],
> > [ignore])
> > +
> > +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> > +
> > +as ovn-sb
> > +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> > +
> > +as ovn-nb
> > +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> > +
> > +as northd
> > +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> > +
> > +as
> > +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> > +/connection dropped.*/d"])
> > +AT_CLEANUP
> > +])
> > diff --git a/tests/test-ovn.c b/tests/test-ovn.c
> > index 2ea68f2124..7954bb98ac 100644
> > --- a/tests/test-ovn.c
> > +++ b/tests/test-ovn.c
> > @@ -1376,6 +1376,9 @@ test_parse_actions(struct ovs_cmdl_context *ctx
> > OVS_UNUSED)
> > .in_port_sec_ptable = OFTABLE_CHK_IN_PORT_SEC,
> > .out_port_sec_ptable = OFTABLE_CHK_OUT_PORT_SEC,
> > .mac_cache_use_table = OFTABLE_MAC_CACHE_USE,
> > + .ct_nw_dst_load_table = OFTABLE_CT_ORIG_NW_DST_LOAD,
> > + .ct_ip6_dst_load_table = OFTABLE_CT_ORIG_IP6_DST_LOAD,
> > + .ct_tp_dst_load_table = OFTABLE_CT_ORIG_TP_DST_LOAD,
> > .lflow_uuid.parts =
> > { 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd},
> > .dp_key = 0xabcdef,
> > diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
> > index f9cc2463b7..806bdf3d9a 100644
> > --- a/utilities/ovn-trace.c
> > +++ b/utilities/ovn-trace.c
> > @@ -3447,6 +3447,12 @@ trace_actions(const struct ovnact *ovnacts, size_t
> > ovnacts_len,
> > break;
> > case OVNACT_MAC_CACHE_USE:
> > break;
> > + case OVNACT_CT_ORIG_NW_DST:
> > + break;
> > + case OVNACT_CT_ORIG_IP6_DST:
> > + break;
> > + case OVNACT_CT_ORIG_TP_DST:
> > + break;
> > }
> > }
> > ofpbuf_uninit(&stack);
>
> Thanks,
> Dumitru
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev