@@ -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),
};
@@ -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;
@@ -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;
+ 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);
}
@@ -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,
@@ -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 */
@@ -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);
}
@@ -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(
@@ -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>
@@ -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)])
@@ -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
@@ -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"])
@@ -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])
+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
+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
+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
+
+yes 1 | head -n 10000 | tr '\n' ' ' | dd of=datafile bs=7373 count=1
+cat datafile datafile datafile datafile > frag_test.expected
+
+# 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])
+
+AT_CHECK([cmp 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
+])
+
+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
+])
@@ -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,
@@ -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);