@@ -86,7 +86,9 @@ struct ovn_extend_table;
OVNACT(OVNFIELD_LOAD, ovnact_load) \
OVNACT(CHECK_PKT_LARGER, ovnact_check_pkt_larger) \
OVNACT(TRIGGER_EVENT, ovnact_controller_event) \
- OVNACT(BIND_VPORT, ovnact_bind_vport)
+ OVNACT(BIND_VPORT, ovnact_bind_vport) \
+ OVNACT(REPLACE_SRC_IP, ovnact_ip_replace) \
+ OVNACT(REPLACE_DST_IP, ovnact_ip_replace)
/* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
enum OVS_PACKED_ENUM ovnact_type {
@@ -279,6 +281,12 @@ struct ovnact_put_opts {
size_t n_options;
};
+/* OVNACT_REPLACE_SRC_IP, OVNACT_REPLACE_DST_IP. */
+struct ovnact_ip_replace {
+ struct ovnact ovnact;
+ ovs_be32 ip;
+};
+
/* Valid arguments to SET_QUEUE action.
*
* QDISC_MIN_QUEUE_ID is the default queue, so user-defined queues should
@@ -871,6 +871,105 @@ ovnact_ct_nat_free(struct ovnact_ct_nat *ct_nat OVS_UNUSED)
{
}
+
+static void
+parse_replace_ip(struct action_context *ctx, struct ovnact_ip_replace *ipr)
+{
+ add_prerequisite(ctx, "ip");
+
+ if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
+ if (ctx->lexer->token.type != LEX_T_INTEGER
+ || ctx->lexer->token.format != LEX_F_IPV4) {
+ lexer_syntax_error(ctx->lexer, "expecting IPv4 address");
+ return;
+ }
+ ipr->ip = ctx->lexer->token.value.ipv4;
+ lexer_get(ctx->lexer);
+
+ if (!lexer_force_match(ctx->lexer, LEX_T_RPAREN)) {
+ return;
+ }
+ } else {
+ lexer_syntax_error(ctx->lexer, "Invalid token");
+ }
+}
+
+static void
+parse_REPLACE_DST_IP(struct action_context *ctx)
+{
+ parse_replace_ip(ctx, ovnact_put_REPLACE_DST_IP(ctx->ovnacts));
+}
+
+static void
+parse_REPLACE_SRC_IP(struct action_context *ctx)
+{
+ parse_replace_ip(ctx, ovnact_put_REPLACE_SRC_IP(ctx->ovnacts));
+}
+
+static void
+format_replace_ip(const struct ovnact_ip_replace *ipr,
+ const char *name, struct ds *s)
+{
+ ds_put_cstr(s, name);
+ ds_put_format(s, "("IP_FMT")", IP_ARGS(ipr->ip));
+ ds_put_char(s, ';');
+}
+
+static void
+format_REPLACE_DST_IP(const struct ovnact_ip_replace *ipr, struct ds *s)
+{
+ format_replace_ip(ipr, "replace_dst_ip", s);
+}
+
+static void
+format_REPLACE_SRC_IP(const struct ovnact_ip_replace *ipr, struct ds *s)
+{
+ format_replace_ip(ipr, "replace_src_ip", s);
+}
+
+static void
+encode_replace_ip(const struct ovnact_ip_replace *ipr,
+ const struct ovnact_encode_params *ep OVS_UNUSED,
+ bool is_src, struct ofpbuf *ofpacts)
+{
+ struct ofpact_ipv4 *replace_ip;
+ const size_t ip_offset = ofpacts->size;
+ ofpbuf_pull(ofpacts, ip_offset);
+
+ if (!is_src) {
+ replace_ip = ofpact_put_SET_IPV4_DST(ofpacts);
+
+ } else {
+ replace_ip = ofpact_put_SET_IPV4_SRC(ofpacts);
+ }
+
+ replace_ip->ipv4 = ipr->ip;
+
+ ofpbuf_push_uninit(ofpacts, ip_offset);
+ ofpact_finish(ofpacts, &replace_ip->ofpact);
+}
+
+static void
+encode_REPLACE_SRC_IP(const struct ovnact_ip_replace *ipr,
+ const struct ovnact_encode_params *ep,
+ struct ofpbuf *ofpacts)
+{
+ encode_replace_ip(ipr, ep, true, ofpacts);
+}
+
+static void
+encode_REPLACE_DST_IP(const struct ovnact_ip_replace *ipr,
+ const struct ovnact_encode_params *ep,
+ struct ofpbuf *ofpacts)
+{
+ encode_replace_ip(ipr, ep, false, ofpacts);
+}
+
+static void
+ovnact_ip_replace_free(struct ovnact_ip_replace *ipr OVS_UNUSED)
+{
+}
+
static void
parse_ct_lb_action(struct action_context *ctx)
{
@@ -2798,6 +2897,10 @@ parse_action(struct action_context *ctx)
parse_trigger_event(ctx, ovnact_put_TRIGGER_EVENT(ctx->ovnacts));
} else if (lexer_match_id(ctx->lexer, "bind_vport")) {
parse_bind_vport(ctx);
+ } else if (lexer_match_id(ctx->lexer, "replace_src_ip")) {
+ parse_REPLACE_SRC_IP(ctx);
+ } else if (lexer_match_id(ctx->lexer, "replace_dst_ip")) {
+ parse_REPLACE_DST_IP(ctx);
} else {
lexer_syntax_error(ctx->lexer, "expecting action");
}
@@ -1432,6 +1432,32 @@ bind_vport("xyzzy",;
bind_vport("xyzzy", inport;
Syntax error at `;' expecting `)'.
+# replace_src_ip
+replace_src_ip(1.2.3.4);
+ encodes as mod_nw_src:1.2.3.4
+ has prereqs ip
+replace_src_ip;
+ Syntax error at `;' Invalid token.
+replace_src_ip(;
+ Syntax error at `;' expecting IPv4 address.
+replace_src_ip(";
+ Input ends inside quoted string.
+replace_src_ip(1.2.3);
+ Invalid numeric constant.
+
+# replace_dst_ip
+replace_dst_ip(1.2.3.4);
+ encodes as mod_nw_dst:1.2.3.4
+ has prereqs ip
+replace_dst_ip;
+ Syntax error at `;' Invalid token.
+replace_dst_ip(;
+ Syntax error at `;' expecting IPv4 address.
+replace_dst_ip(";
+ Input ends inside quoted string.
+replace_dst_ip(1.2.3);
+ Invalid numeric constant.
+
# Miscellaneous negative tests.
;
Syntax error at `;'.
@@ -2147,6 +2147,12 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
case OVNACT_BIND_VPORT:
break;
+
+ case OVNACT_REPLACE_SRC_IP:
+ break;
+
+ case OVNACT_REPLACE_DST_IP:
+ break;
}
}
ds_destroy(&s);
This patch adds 2 new ovn actions, "replace_src_ip" and "replace_dst_ip" These actions map to mod_nw_src and mod_nw_dst OVS actions respectively. These actions simply replace the source and destination IPs of the packets, while changing the L3 and L4 checksums. Signed-off-by: Ankur Sharma <ankur.sharma@nutanix.com> --- include/ovn/actions.h | 10 ++++- lib/actions.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/ovn.at | 26 +++++++++++++ utilities/ovn-trace.c | 6 +++ 4 files changed, 144 insertions(+), 1 deletion(-)