|
|
ebb439 |
From c55da56e570b50cfc33358341f17f2dc738e8b33 Mon Sep 17 00:00:00 2001
|
|
|
ebb439 |
From: Numan Siddique <numans@ovn.org>
|
|
|
ebb439 |
Date: Thu, 12 Nov 2020 17:26:57 +0530
|
|
|
ebb439 |
Subject: [PATCH 07/10] actions: Add new actions chk_lb_hairpin,
|
|
|
ebb439 |
chk_lb_hairpin_reply and ct_snat_to_vip.
|
|
|
ebb439 |
|
|
|
ebb439 |
The action - chk_lb_hairpin checks if the packet destined to a load balancer VIP
|
|
|
ebb439 |
is to be hairpinned back to the same destination and if so, sets the destination register
|
|
|
ebb439 |
bit to 1.
|
|
|
ebb439 |
|
|
|
ebb439 |
The action - chk_lb_hairpin_reply checks if the packet is a reply of the hairpinned
|
|
|
ebb439 |
packet. If so, it sets the destination register bit to 1.
|
|
|
ebb439 |
|
|
|
ebb439 |
The action ct_snat_to_vip snats the source IP to the load balancer VIP if chk_lb_hairpin()
|
|
|
ebb439 |
returned true.
|
|
|
ebb439 |
|
|
|
ebb439 |
These actions will be used in the upcoming patch by ovn-northd in the hairpin logical flows.
|
|
|
ebb439 |
This helps in reducing lots of hairpin logical flows.
|
|
|
ebb439 |
|
|
|
ebb439 |
Acked-by: Dumitru Ceara <dceara@redhat.com>
|
|
|
ebb439 |
Acked-by: Mark Michelson <mmichels@redhat.com>
|
|
|
ebb439 |
Signed-off-by: Numan Siddique <numans@ovn.org>
|
|
|
ebb439 |
|
|
|
ebb439 |
(cherry-picked from master commit fc219d84b667a48760c62e41dbc25fcb5748d41a)
|
|
|
ebb439 |
---
|
|
|
ebb439 |
controller/lflow.c | 3 ++
|
|
|
ebb439 |
include/ovn/actions.h | 15 ++++--
|
|
|
ebb439 |
lib/actions.c | 116 ++++++++++++++++++++++++++++++++++++++----
|
|
|
ebb439 |
ovn-sb.xml | 37 ++++++++++++++
|
|
|
ebb439 |
tests/ovn.at | 39 ++++++++++++++
|
|
|
ebb439 |
tests/test-ovn.c | 3 ++
|
|
|
ebb439 |
utilities/ovn-trace.c | 65 ++++++++++++++++++++++-
|
|
|
ebb439 |
7 files changed, 265 insertions(+), 13 deletions(-)
|
|
|
ebb439 |
|
|
|
ebb439 |
diff --git a/controller/lflow.c b/controller/lflow.c
|
|
|
ebb439 |
index 633fdfb7f..7ab6a686b 100644
|
|
|
ebb439 |
--- a/controller/lflow.c
|
|
|
ebb439 |
+++ b/controller/lflow.c
|
|
|
ebb439 |
@@ -698,6 +698,9 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow,
|
|
|
ebb439 |
.output_ptable = output_ptable,
|
|
|
ebb439 |
.mac_bind_ptable = OFTABLE_MAC_BINDING,
|
|
|
ebb439 |
.mac_lookup_ptable = OFTABLE_MAC_LOOKUP,
|
|
|
ebb439 |
+ .lb_hairpin_ptable = OFTABLE_CHK_LB_HAIRPIN,
|
|
|
ebb439 |
+ .lb_hairpin_reply_ptable = OFTABLE_CHK_LB_HAIRPIN_REPLY,
|
|
|
ebb439 |
+ .ct_snat_vip_ptable = OFTABLE_CT_SNAT_FOR_VIP,
|
|
|
ebb439 |
};
|
|
|
ebb439 |
ovnacts_encode(ovnacts->data, ovnacts->size, &ep, &ofpacts);
|
|
|
ebb439 |
|
|
|
ebb439 |
diff --git a/include/ovn/actions.h b/include/ovn/actions.h
|
|
|
ebb439 |
index b4e5acabb..630bbe79e 100644
|
|
|
ebb439 |
--- a/include/ovn/actions.h
|
|
|
ebb439 |
+++ b/include/ovn/actions.h
|
|
|
ebb439 |
@@ -83,7 +83,7 @@ struct ovn_extend_table;
|
|
|
ebb439 |
OVNACT(PUT_DHCPV4_OPTS, ovnact_put_opts) \
|
|
|
ebb439 |
OVNACT(PUT_DHCPV6_OPTS, ovnact_put_opts) \
|
|
|
ebb439 |
OVNACT(SET_QUEUE, ovnact_set_queue) \
|
|
|
ebb439 |
- OVNACT(DNS_LOOKUP, ovnact_dns_lookup) \
|
|
|
ebb439 |
+ OVNACT(DNS_LOOKUP, ovnact_result) \
|
|
|
ebb439 |
OVNACT(LOG, ovnact_log) \
|
|
|
ebb439 |
OVNACT(PUT_ND_RA_OPTS, ovnact_put_opts) \
|
|
|
ebb439 |
OVNACT(ND_NS, ovnact_nest) \
|
|
|
ebb439 |
@@ -97,6 +97,9 @@ struct ovn_extend_table;
|
|
|
ebb439 |
OVNACT(DHCP6_REPLY, ovnact_null) \
|
|
|
ebb439 |
OVNACT(ICMP6_ERROR, ovnact_nest) \
|
|
|
ebb439 |
OVNACT(REJECT, ovnact_nest) \
|
|
|
ebb439 |
+ OVNACT(CHK_LB_HAIRPIN, ovnact_result) \
|
|
|
ebb439 |
+ OVNACT(CHK_LB_HAIRPIN_REPLY, ovnact_result) \
|
|
|
ebb439 |
+ OVNACT(CT_SNAT_TO_VIP, ovnact_null) \
|
|
|
ebb439 |
|
|
|
ebb439 |
/* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
|
|
|
ebb439 |
enum OVS_PACKED_ENUM ovnact_type {
|
|
|
ebb439 |
@@ -338,8 +341,8 @@ struct ovnact_set_queue {
|
|
|
ebb439 |
uint16_t queue_id;
|
|
|
ebb439 |
};
|
|
|
ebb439 |
|
|
|
ebb439 |
-/* OVNACT_DNS_LOOKUP. */
|
|
|
ebb439 |
-struct ovnact_dns_lookup {
|
|
|
ebb439 |
+/* OVNACT_DNS_LOOKUP, OVNACT_CHK_LB_HAIRPIN, OVNACT_CHK_LB_HAIRPIN_REPLY. */
|
|
|
ebb439 |
+struct ovnact_result {
|
|
|
ebb439 |
struct ovnact ovnact;
|
|
|
ebb439 |
struct expr_field dst; /* 1-bit destination field. */
|
|
|
ebb439 |
};
|
|
|
ebb439 |
@@ -727,6 +730,12 @@ struct ovnact_encode_params {
|
|
|
ebb439 |
resubmit. */
|
|
|
ebb439 |
uint8_t mac_lookup_ptable; /* OpenFlow table for
|
|
|
ebb439 |
'lookup_arp'/'lookup_nd' to resubmit. */
|
|
|
ebb439 |
+ uint8_t lb_hairpin_ptable; /* OpenFlow table for
|
|
|
ebb439 |
+ * 'chk_lb_hairpin' to resubmit. */
|
|
|
ebb439 |
+ uint8_t lb_hairpin_reply_ptable; /* OpenFlow table for
|
|
|
ebb439 |
+ * 'chk_lb_hairpin_reply' to resubmit. */
|
|
|
ebb439 |
+ uint8_t ct_snat_vip_ptable; /* OpenFlow table for
|
|
|
ebb439 |
+ * 'ct_snat_to_vip' to resubmit. */
|
|
|
ebb439 |
};
|
|
|
ebb439 |
|
|
|
ebb439 |
void ovnacts_encode(const struct ovnact[], size_t ovnacts_len,
|
|
|
ebb439 |
diff --git a/lib/actions.c b/lib/actions.c
|
|
|
ebb439 |
index 23e54ef2a..015bcbc4d 100644
|
|
|
ebb439 |
--- a/lib/actions.c
|
|
|
ebb439 |
+++ b/lib/actions.c
|
|
|
ebb439 |
@@ -2655,13 +2655,14 @@ ovnact_set_queue_free(struct ovnact_set_queue *a OVS_UNUSED)
|
|
|
ebb439 |
}
|
|
|
ebb439 |
|
|
|
ebb439 |
static void
|
|
|
ebb439 |
-parse_dns_lookup(struct action_context *ctx, const struct expr_field *dst,
|
|
|
ebb439 |
- struct ovnact_dns_lookup *dl)
|
|
|
ebb439 |
+parse_ovnact_result(struct action_context *ctx, const char *name,
|
|
|
ebb439 |
+ const char *prereq, const struct expr_field *dst,
|
|
|
ebb439 |
+ struct ovnact_result *res)
|
|
|
ebb439 |
{
|
|
|
ebb439 |
- lexer_get(ctx->lexer); /* Skip dns_lookup. */
|
|
|
ebb439 |
+ lexer_get(ctx->lexer); /* Skip action name. */
|
|
|
ebb439 |
lexer_get(ctx->lexer); /* Skip '('. */
|
|
|
ebb439 |
if (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
|
|
|
ebb439 |
- lexer_error(ctx->lexer, "dns_lookup doesn't take any parameters");
|
|
|
ebb439 |
+ lexer_error(ctx->lexer, "%s doesn't take any parameters", name);
|
|
|
ebb439 |
return;
|
|
|
ebb439 |
}
|
|
|
ebb439 |
/* Validate that the destination is a 1-bit, modifiable field. */
|
|
|
ebb439 |
@@ -2671,19 +2672,29 @@ parse_dns_lookup(struct action_context *ctx, const struct expr_field *dst,
|
|
|
ebb439 |
free(error);
|
|
|
ebb439 |
return;
|
|
|
ebb439 |
}
|
|
|
ebb439 |
- dl->dst = *dst;
|
|
|
ebb439 |
- add_prerequisite(ctx, "udp");
|
|
|
ebb439 |
+ res->dst = *dst;
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ if (prereq) {
|
|
|
ebb439 |
+ add_prerequisite(ctx, prereq);
|
|
|
ebb439 |
+ }
|
|
|
ebb439 |
}
|
|
|
ebb439 |
|
|
|
ebb439 |
static void
|
|
|
ebb439 |
-format_DNS_LOOKUP(const struct ovnact_dns_lookup *dl, struct ds *s)
|
|
|
ebb439 |
+parse_dns_lookup(struct action_context *ctx, const struct expr_field *dst,
|
|
|
ebb439 |
+ struct ovnact_result *dl)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ parse_ovnact_result(ctx, "dns_lookup", "udp", dst, dl);
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+format_DNS_LOOKUP(const struct ovnact_result *dl, struct ds *s)
|
|
|
ebb439 |
{
|
|
|
ebb439 |
expr_field_format(&dl->dst, s);
|
|
|
ebb439 |
ds_put_cstr(s, " = dns_lookup();");
|
|
|
ebb439 |
}
|
|
|
ebb439 |
|
|
|
ebb439 |
static void
|
|
|
ebb439 |
-encode_DNS_LOOKUP(const struct ovnact_dns_lookup *dl,
|
|
|
ebb439 |
+encode_DNS_LOOKUP(const struct ovnact_result *dl,
|
|
|
ebb439 |
const struct ovnact_encode_params *ep OVS_UNUSED,
|
|
|
ebb439 |
struct ofpbuf *ofpacts)
|
|
|
ebb439 |
{
|
|
|
ebb439 |
@@ -2700,7 +2711,7 @@ encode_DNS_LOOKUP(const struct ovnact_dns_lookup *dl,
|
|
|
ebb439 |
|
|
|
ebb439 |
|
|
|
ebb439 |
static void
|
|
|
ebb439 |
-ovnact_dns_lookup_free(struct ovnact_dns_lookup *dl OVS_UNUSED)
|
|
|
ebb439 |
+ovnact_result_free(struct ovnact_result *dl OVS_UNUSED)
|
|
|
ebb439 |
{
|
|
|
ebb439 |
}
|
|
|
ebb439 |
|
|
|
ebb439 |
@@ -3472,6 +3483,83 @@ ovnact_fwd_group_free(struct ovnact_fwd_group *fwd_group)
|
|
|
ebb439 |
free(fwd_group->child_ports);
|
|
|
ebb439 |
}
|
|
|
ebb439 |
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+parse_chk_lb_hairpin(struct action_context *ctx, const struct expr_field *dst,
|
|
|
ebb439 |
+ struct ovnact_result *res)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ parse_ovnact_result(ctx, "chk_lb_hairpin", NULL, dst, res);
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+parse_chk_lb_hairpin_reply(struct action_context *ctx,
|
|
|
ebb439 |
+ const struct expr_field *dst,
|
|
|
ebb439 |
+ struct ovnact_result *res)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ parse_ovnact_result(ctx, "chk_lb_hairpin_reply", NULL, dst, res);
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+format_CHK_LB_HAIRPIN(const struct ovnact_result *res, struct ds *s)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ expr_field_format(&res->dst, s);
|
|
|
ebb439 |
+ ds_put_cstr(s, " = chk_lb_hairpin();");
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+format_CHK_LB_HAIRPIN_REPLY(const struct ovnact_result *res, struct ds *s)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ expr_field_format(&res->dst, s);
|
|
|
ebb439 |
+ ds_put_cstr(s, " = chk_lb_hairpin_reply();");
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+encode_chk_lb_hairpin__(const struct ovnact_result *res,
|
|
|
ebb439 |
+ uint8_t hairpin_table,
|
|
|
ebb439 |
+ struct ofpbuf *ofpacts)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ struct mf_subfield dst = expr_resolve_field(&res->dst);
|
|
|
ebb439 |
+ ovs_assert(dst.field);
|
|
|
ebb439 |
+ put_load(0, MFF_LOG_FLAGS, MLF_LOOKUP_LB_HAIRPIN_BIT, 1, ofpacts);
|
|
|
ebb439 |
+ emit_resubmit(ofpacts, hairpin_table);
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts);
|
|
|
ebb439 |
+ orm->dst = dst;
|
|
|
ebb439 |
+ orm->src.field = mf_from_id(MFF_LOG_FLAGS);
|
|
|
ebb439 |
+ orm->src.ofs = MLF_LOOKUP_LB_HAIRPIN_BIT;
|
|
|
ebb439 |
+ orm->src.n_bits = 1;
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+encode_CHK_LB_HAIRPIN(const struct ovnact_result *res,
|
|
|
ebb439 |
+ const struct ovnact_encode_params *ep,
|
|
|
ebb439 |
+ struct ofpbuf *ofpacts)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ encode_chk_lb_hairpin__(res, ep->lb_hairpin_ptable, ofpacts);
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+encode_CHK_LB_HAIRPIN_REPLY(const struct ovnact_result *res,
|
|
|
ebb439 |
+ const struct ovnact_encode_params *ep,
|
|
|
ebb439 |
+ struct ofpbuf *ofpacts)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ encode_chk_lb_hairpin__(res, ep->lb_hairpin_reply_ptable, ofpacts);
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+format_CT_SNAT_TO_VIP(const struct ovnact_null *null OVS_UNUSED, struct ds *s)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ ds_put_cstr(s, "ct_snat_to_vip;");
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+encode_CT_SNAT_TO_VIP(const struct ovnact_null *null OVS_UNUSED,
|
|
|
ebb439 |
+ const struct ovnact_encode_params *ep,
|
|
|
ebb439 |
+ struct ofpbuf *ofpacts)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ emit_resubmit(ofpacts, ep->ct_snat_vip_ptable);
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
/* Parses an assignment or exchange or put_dhcp_opts action. */
|
|
|
ebb439 |
static void
|
|
|
ebb439 |
parse_set_action(struct action_context *ctx)
|
|
|
ebb439 |
@@ -3524,6 +3612,14 @@ parse_set_action(struct action_context *ctx)
|
|
|
ebb439 |
&& lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
|
|
|
ebb439 |
parse_lookup_mac_bind_ip(ctx, &lhs, 128,
|
|
|
ebb439 |
ovnact_put_LOOKUP_ND_IP(ctx->ovnacts));
|
|
|
ebb439 |
+ } else if (!strcmp(ctx->lexer->token.s, "chk_lb_hairpin")
|
|
|
ebb439 |
+ && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
|
|
|
ebb439 |
+ parse_chk_lb_hairpin(ctx, &lhs,
|
|
|
ebb439 |
+ ovnact_put_CHK_LB_HAIRPIN(ctx->ovnacts));
|
|
|
ebb439 |
+ } else if (!strcmp(ctx->lexer->token.s, "chk_lb_hairpin_reply")
|
|
|
ebb439 |
+ && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
|
|
|
ebb439 |
+ parse_chk_lb_hairpin_reply(
|
|
|
ebb439 |
+ ctx, &lhs, ovnact_put_CHK_LB_HAIRPIN_REPLY(ctx->ovnacts));
|
|
|
ebb439 |
} else {
|
|
|
ebb439 |
parse_assignment_action(ctx, false, &lhs;;
|
|
|
ebb439 |
}
|
|
|
ebb439 |
@@ -3610,6 +3706,8 @@ parse_action(struct action_context *ctx)
|
|
|
ebb439 |
ovnact_put_DHCP6_REPLY(ctx->ovnacts);
|
|
|
ebb439 |
} else if (lexer_match_id(ctx->lexer, "reject")) {
|
|
|
ebb439 |
parse_REJECT(ctx);
|
|
|
ebb439 |
+ } else if (lexer_match_id(ctx->lexer, "ct_snat_to_vip")) {
|
|
|
ebb439 |
+ ovnact_put_CT_SNAT_TO_VIP(ctx->ovnacts);
|
|
|
ebb439 |
} else {
|
|
|
ebb439 |
lexer_syntax_error(ctx->lexer, "expecting action");
|
|
|
ebb439 |
}
|
|
|
ebb439 |
diff --git a/ovn-sb.xml b/ovn-sb.xml
|
|
|
ebb439 |
index 7fa0496fe..7d38c7e3f 100644
|
|
|
ebb439 |
--- a/ovn-sb.xml
|
|
|
ebb439 |
+++ b/ovn-sb.xml
|
|
|
ebb439 |
@@ -2325,6 +2325,43 @@ tcp.flags = RST;
|
|
|
ebb439 |
Delegation Router and managed IPv6 Prefix delegation state machine
|
|
|
ebb439 |
|
|
|
ebb439 |
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ R = chk_lb_hairpin();
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ This action checks if the packet under consideration was destined
|
|
|
ebb439 |
+ to a load balancer VIP and it is hairpinned, i.e., after load
|
|
|
ebb439 |
+ balancing the destination IP matches the source IP. If it is so,
|
|
|
ebb439 |
+ then the 1-bit destination register R is set to 1.
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ R = chk_lb_hairpin_reply();
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ This action checks if the packet under consideration is from
|
|
|
ebb439 |
+ one of the backend IP of a load balancer VIP and the destination IP
|
|
|
ebb439 |
+ is the load balancer VIP. If it is so, then the 1-bit destination
|
|
|
ebb439 |
+ register R is set to 1.
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ R = ct_snat_to_vip;
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ This action sends the packet through the SNAT zone to change the
|
|
|
ebb439 |
+ source IP address of the packet to the load balancer VIP if the
|
|
|
ebb439 |
+ original destination IP was load balancer VIP and commits the
|
|
|
ebb439 |
+ connection. This action applies successfully only for the
|
|
|
ebb439 |
+ hairpinned traffic i.e if the action chk_lb_hairpin
|
|
|
ebb439 |
+ returned success. This action doesn't take any arguments and it
|
|
|
ebb439 |
+ determines the SNAT IP internally.
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ The packet is not automatically sent to the next table. The caller
|
|
|
ebb439 |
+ has to execute the next; action explicitly after this
|
|
|
ebb439 |
+ action to advance the packet to the next stage.
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+
|
|
|
ebb439 |
|
|
|
ebb439 |
</column>
|
|
|
ebb439 |
|
|
|
ebb439 |
diff --git a/tests/ovn.at b/tests/ovn.at
|
|
|
ebb439 |
index 5cb96bae6..8dbb13d3a 100644
|
|
|
ebb439 |
--- a/tests/ovn.at
|
|
|
ebb439 |
+++ b/tests/ovn.at
|
|
|
ebb439 |
@@ -1716,6 +1716,45 @@ fwd_group(liveness="false", childports="eth0", "lsp1");
|
|
|
ebb439 |
handle_dhcpv6_reply;
|
|
|
ebb439 |
encodes as controller(userdata=00.00.00.13.00.00.00.00)
|
|
|
ebb439 |
|
|
|
ebb439 |
+# chk_lb_hairpin
|
|
|
ebb439 |
+reg0[0] = chk_lb_hairpin();
|
|
|
ebb439 |
+ encodes as set_field:0/0x80->reg10,resubmit(,68),move:NXM_NX_REG10[7]->NXM_NX_XXREG0[96]
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+reg2[2] = chk_lb_hairpin();
|
|
|
ebb439 |
+ encodes as set_field:0/0x80->reg10,resubmit(,68),move:NXM_NX_REG10[7]->NXM_NX_XXREG0[34]
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+reg0 = chk_lb_hairpin();
|
|
|
ebb439 |
+ Cannot use 32-bit field reg0[0..31] where 1-bit field is required.
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+reg0[0] = chk_lb_hairpin(foo);
|
|
|
ebb439 |
+ chk_lb_hairpin doesn't take any parameters
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+chk_lb_hairpin;
|
|
|
ebb439 |
+ Syntax error at `chk_lb_hairpin' expecting action.
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+# chk_lb_hairpin_reply
|
|
|
ebb439 |
+reg0[0] = chk_lb_hairpin_reply();
|
|
|
ebb439 |
+ encodes as set_field:0/0x80->reg10,resubmit(,69),move:NXM_NX_REG10[7]->NXM_NX_XXREG0[96]
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+reg2[2..3] = chk_lb_hairpin_reply();
|
|
|
ebb439 |
+ Cannot use 2-bit field reg2[2..3] where 1-bit field is required.
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+reg0 = chk_lb_hairpin_reply();
|
|
|
ebb439 |
+ Cannot use 32-bit field reg0[0..31] where 1-bit field is required.
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+reg0[0] = chk_lb_hairpin_reply(foo);
|
|
|
ebb439 |
+ chk_lb_hairpin_reply doesn't take any parameters
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+chk_lb_hairpin_reply;
|
|
|
ebb439 |
+ Syntax error at `chk_lb_hairpin_reply' expecting action.
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+# ct_snat_to_vip
|
|
|
ebb439 |
+ct_snat_to_vip;
|
|
|
ebb439 |
+ encodes as resubmit(,70)
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ct_snat_to_vip(foo);
|
|
|
ebb439 |
+ Syntax error at `(' expecting `;'.
|
|
|
ebb439 |
+
|
|
|
ebb439 |
# Miscellaneous negative tests.
|
|
|
ebb439 |
;
|
|
|
ebb439 |
Syntax error at `;'.
|
|
|
ebb439 |
diff --git a/tests/test-ovn.c b/tests/test-ovn.c
|
|
|
ebb439 |
index 80d99b7a8..6662ced54 100644
|
|
|
ebb439 |
--- a/tests/test-ovn.c
|
|
|
ebb439 |
+++ b/tests/test-ovn.c
|
|
|
ebb439 |
@@ -1342,6 +1342,9 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED)
|
|
|
ebb439 |
.output_ptable = OFTABLE_SAVE_INPORT,
|
|
|
ebb439 |
.mac_bind_ptable = OFTABLE_MAC_BINDING,
|
|
|
ebb439 |
.mac_lookup_ptable = OFTABLE_MAC_LOOKUP,
|
|
|
ebb439 |
+ .lb_hairpin_ptable = OFTABLE_CHK_LB_HAIRPIN,
|
|
|
ebb439 |
+ .lb_hairpin_reply_ptable = OFTABLE_CHK_LB_HAIRPIN_REPLY,
|
|
|
ebb439 |
+ .ct_snat_vip_ptable = OFTABLE_CT_SNAT_FOR_VIP,
|
|
|
ebb439 |
};
|
|
|
ebb439 |
struct ofpbuf ofpacts;
|
|
|
ebb439 |
ofpbuf_init(&ofpacts, 0);
|
|
|
ebb439 |
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
|
|
|
ebb439 |
index 5d54c0fd8..cc1cd1b16 100644
|
|
|
ebb439 |
--- a/utilities/ovn-trace.c
|
|
|
ebb439 |
+++ b/utilities/ovn-trace.c
|
|
|
ebb439 |
@@ -1990,7 +1990,7 @@ execute_next(const struct ovnact_next *next,
|
|
|
ebb439 |
|
|
|
ebb439 |
|
|
|
ebb439 |
static void
|
|
|
ebb439 |
-execute_dns_lookup(const struct ovnact_dns_lookup *dl, struct flow *uflow,
|
|
|
ebb439 |
+execute_dns_lookup(const struct ovnact_result *dl, struct flow *uflow,
|
|
|
ebb439 |
struct ovs_list *super)
|
|
|
ebb439 |
{
|
|
|
ebb439 |
struct mf_subfield sf = expr_resolve_field(&dl->dst);
|
|
|
ebb439 |
@@ -2222,6 +2222,57 @@ execute_ovnfield_load(const struct ovnact_load *load,
|
|
|
ebb439 |
}
|
|
|
ebb439 |
}
|
|
|
ebb439 |
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+execute_chk_lb_hairpin(const struct ovnact_result *dl, struct flow *uflow,
|
|
|
ebb439 |
+ struct ovs_list *super)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ int family = (uflow->dl_type == htons(ETH_TYPE_IP) ? AF_INET
|
|
|
ebb439 |
+ : uflow->dl_type == htons(ETH_TYPE_IPV6) ? AF_INET6
|
|
|
ebb439 |
+ : AF_UNSPEC);
|
|
|
ebb439 |
+ uint8_t res = 0;
|
|
|
ebb439 |
+ if (family != AF_UNSPEC && uflow->ct_state & CS_DST_NAT) {
|
|
|
ebb439 |
+ if (family == AF_INET) {
|
|
|
ebb439 |
+ res = (uflow->nw_src == uflow->nw_dst) ? 1 : 0;
|
|
|
ebb439 |
+ } else {
|
|
|
ebb439 |
+ res = ipv6_addr_equals(&uflow->ipv6_src, &uflow->ipv6_dst) ? 1 : 0;
|
|
|
ebb439 |
+ }
|
|
|
ebb439 |
+ }
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ struct mf_subfield sf = expr_resolve_field(&dl->dst);
|
|
|
ebb439 |
+ union mf_subvalue sv = { .u8_val = res };
|
|
|
ebb439 |
+ mf_write_subfield_flow(&sf, &sv, uflow);
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ struct ds s = DS_EMPTY_INITIALIZER;
|
|
|
ebb439 |
+ expr_field_format(&dl->dst, &s);
|
|
|
ebb439 |
+ ovntrace_node_append(super, OVNTRACE_NODE_MODIFY,
|
|
|
ebb439 |
+ "%s = %d", ds_cstr(&s), res);
|
|
|
ebb439 |
+ ds_destroy(&s);
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+execute_chk_lb_hairpin_reply(const struct ovnact_result *dl,
|
|
|
ebb439 |
+ struct flow *uflow,
|
|
|
ebb439 |
+ struct ovs_list *super)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ struct mf_subfield sf = expr_resolve_field(&dl->dst);
|
|
|
ebb439 |
+ union mf_subvalue sv = { .u8_val = 0 };
|
|
|
ebb439 |
+ mf_write_subfield_flow(&sf, &sv, uflow);
|
|
|
ebb439 |
+ ovntrace_node_append(super, OVNTRACE_NODE_ERROR,
|
|
|
ebb439 |
+ "*** chk_lb_hairpin_reply action not implemented");
|
|
|
ebb439 |
+ struct ds s = DS_EMPTY_INITIALIZER;
|
|
|
ebb439 |
+ expr_field_format(&dl->dst, &s);
|
|
|
ebb439 |
+ ovntrace_node_append(super, OVNTRACE_NODE_MODIFY,
|
|
|
ebb439 |
+ "%s = 0", ds_cstr(&s);;
|
|
|
ebb439 |
+ ds_destroy(&s);
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+static void
|
|
|
ebb439 |
+execute_ct_snat_to_vip(struct flow *uflow OVS_UNUSED, struct ovs_list *super)
|
|
|
ebb439 |
+{
|
|
|
ebb439 |
+ ovntrace_node_append(super, OVNTRACE_NODE_ERROR,
|
|
|
ebb439 |
+ "*** ct_snat_to_vip action not implemented");
|
|
|
ebb439 |
+}
|
|
|
ebb439 |
+
|
|
|
ebb439 |
static void
|
|
|
ebb439 |
trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
|
|
|
ebb439 |
const struct ovntrace_datapath *dp, struct flow *uflow,
|
|
|
ebb439 |
@@ -2438,6 +2489,18 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
|
|
|
ebb439 |
pipeline, super);
|
|
|
ebb439 |
break;
|
|
|
ebb439 |
|
|
|
ebb439 |
+ case OVNACT_CHK_LB_HAIRPIN:
|
|
|
ebb439 |
+ execute_chk_lb_hairpin(ovnact_get_CHK_LB_HAIRPIN(a), uflow, super);
|
|
|
ebb439 |
+ break;
|
|
|
ebb439 |
+
|
|
|
ebb439 |
+ case OVNACT_CHK_LB_HAIRPIN_REPLY:
|
|
|
ebb439 |
+ execute_chk_lb_hairpin_reply(ovnact_get_CHK_LB_HAIRPIN_REPLY(a),
|
|
|
ebb439 |
+ uflow, super);
|
|
|
ebb439 |
+ break;
|
|
|
ebb439 |
+ case OVNACT_CT_SNAT_TO_VIP:
|
|
|
ebb439 |
+ execute_ct_snat_to_vip(uflow, super);
|
|
|
ebb439 |
+ break;
|
|
|
ebb439 |
+
|
|
|
ebb439 |
case OVNACT_TRIGGER_EVENT:
|
|
|
ebb439 |
break;
|
|
|
ebb439 |
|
|
|
ebb439 |
--
|
|
|
ebb439 |
2.28.0
|
|
|
ebb439 |
|