On 11/7/24 21:59, [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. > > In order to not break hardware offload on certain smart nics, care is taken > to match on these fields only for fragmented packets. > > Note: 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 > > 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]> > --- > > v1 -> v2 > ------ > * Addressed review comments from Dumitru.
Hi Numan, >From my perspective this looks good. I did trigger a recheck of the ovn-kubernetes CI jobs (one was timing out but I think that's just an unrelated flake). I left a few small comments below which can be addressed at merge time. With them addressed: Acked-by: Dumitru Ceara <[email protected]> Thanks, Dumitru > > 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 | 143 +++++++++++++++++++++++++++++++++++ > tests/test-ovn.c | 3 + > utilities/ovn-trace.c | 6 ++ > 14 files changed, 514 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 c6db4f376b..3ca4e07835 100644 > --- a/controller/physical.c > +++ b/controller/physical.c > @@ -2769,5 +2769,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.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_init_catchall(&match); > + ofpbuf_clear(&ofpacts); > + > + /* Add the flow: > + * match = (ct.trk && ct.est), 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.est && 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.est && 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. */ Nit: the indentation of the multiline comments is a bit off. > }; > > 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", > + 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 7d11663ece..f419b66121 100644 > --- a/tests/ovn-macros.at > +++ b/tests/ovn-macros.at > @@ -1226,5 +1226,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 a8eb5b0a60..15b78f4c37 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]) > @@ -35773,7 +35821,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..6a09ccdb3d 100644 > --- a/tests/system-ovn-kmod.at > +++ b/tests/system-ovn-kmod.at > @@ -1027,3 +1027,146 @@ 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_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. > +check ovn-nbctl ls-add sw > +check ovn-nbctl lsp-add sw lsp -- lsp-set-addresses lsp 00:00:00:00:00:01 > +check ovn-nbctl lb-add lb-ipv4-udp 88.88.88.88:4040 42.42.42.1:2021 udp > +check ovn-nbctl ls-lb-add sw lb-ipv4-udp > + > +check ovn-nbctl lr-add rtr > +check ovn-nbctl lrp-add rtr rtr-sw 00:00:00:00:01:00 42.42.42.254/24 > +check 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 sync Nit: missing check. > + > +printf %8000s > datafile > +printf %32000s > frag_test_srv.expected > +printf %16000s > frag_test_client.expected > + > +# Start IPv4 UDP server on lsp. Nit: either we add a comment about the client or we remove this one. > + > +NETNS_DAEMONIZE([lsp], [nc -e /bin/cat -u -v -l 42.42.42.1 2021 -o > udp_frag_test_srv.rcvd], [lsp-nc.pid]) Nit: extra whitespace after -l. > +NS_CHECK_EXEC([lsp], [(cat datafile; sleep 3) | nc -u 88.88.88.88 4040 -p > 20000 -o udp_frag_test_c1.recvd], [0], [ignore], [ignore]) > +NS_CHECK_EXEC([lsp], [(cat datafile; sleep 3) | nc -u 88.88.88.88 4040 -p > 20000 -o udp_frag_test_c2.recvd], [0], [ignore], [ignore]) Maybe we need a small comment above these two lines mentioning that we're reusing the same port (from the server perspective it's the same session). > + > +check cmp frag_test_srv.expected udp_frag_test_srv.rcvd > +check cmp frag_test_client.expected udp_frag_test_c1.recvd > +check cmp frag_test_client.expected udp_frag_test_c2.recvd > + > +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. > +check ovn-nbctl ls-add sw > +check ovn-nbctl lsp-add sw lsp -- lsp-set-addresses lsp 00:00:00:00:00:01 > +check ovn-nbctl lb-add lb-ipv6-udp [[8800::0088]]:4040 [[4200::1]]:2021 > udp > +check ovn-nbctl ls-lb-add sw lb-ipv6-udp > + > +check ovn-nbctl lr-add rtr > +check ovn-nbctl lrp-add rtr rtr-sw 00:00:00:00:01:00 4200::00ff/64 > +check 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 Nit: missing check. > + > +ADD_NAMESPACES(lsp) > +ADD_VETH(lsp, lsp, br-int, "4200::1/64", "00:00:00:00:00:01", "4200::00ff", > "nodad") > + > +printf %8000s > datafile > +printf %32000s > frag_test_srv.expected > +printf %16000s > frag_test_client.expected > + > +# Start IPv6 UDP server on lsp. > +NETNS_DAEMONIZE([lsp], [nc -e /bin/cat -u -v -l 4200::1 2021 -o > udp_frag_test_srv.rcvd], [lsp-nc.pid]) > + > +NS_CHECK_EXEC([lsp], [(cat datafile; sleep 3) | nc -6 -u 8800::0088 4040 -p > 20000 -o udp_frag_test_c1.recvd], [0], [ignore], [ignore]) > +NS_CHECK_EXEC([lsp], [(cat datafile; sleep 3) | nc -6 -u 8800::0088 4040 -p > 20000 -o udp_frag_test_c2.recvd], [0], [ignore], [ignore]) > + Here too. > +check cmp frag_test_srv.expected udp_frag_test_srv.rcvd > +check cmp frag_test_client.expected udp_frag_test_c1.recvd > +check cmp frag_test_client.expected udp_frag_test_c2.recvd > + > +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); _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
