diff options
author | Peng He <xnhp0320@gmail.com> | 2021-08-01 21:09:11 +0800 |
---|---|---|
committer | Ilya Maximets <i.maximets@ovn.org> | 2021-10-13 22:17:30 +0200 |
commit | c1fdb83471b0713c61dd1cd2c26edc394a41386c (patch) | |
tree | 2fb13f7e5e4cc9a02ede3b0785e6fe6d8c44abbc /ofproto/ofproto-dpif-xlate.c | |
parent | 02aebad3fba6c4be3766ce91ee9029208f1f423e (diff) | |
download | openvswitch-c1fdb83471b0713c61dd1cd2c26edc394a41386c.tar.gz |
ofproto-dpif-xlate: Fix zone set from non-frozen-metadata fields.
CT zone could be set from a field that is not included in frozen
metadata. Consider the example rules which are typically seen in
OpenStack security group rules:
priority=100,in_port=1,tcp,ct_state=-trk,action=ct(zone=5,table=0)
priority=100,in_port=1,tcp,ct_state=+trk,action=ct(commit,zone=NXM_NX_CT_ZONE[]),2
The zone is set from the first rule's ct action. These two rules will
generate two megaflows: the first one uses zone=5 to query the CT module,
the second one sets the zone-id from the first megaflow and commit to CT.
The current implementation will generate a megaflow that does not use
ct_zone=5 as a match, but directly commit into the ct using zone=5, as zone is
set by an Imm not a field.
Consider a situation that one changes the zone id (for example to 15)
in the first rule, however, still keep the second rule unchanged. During
this change, there is traffic hitting the two generated megaflows, the
revaldiator would revalidate all megaflows, however, the revalidator will
not change the second megaflow, because zone=5 is recorded in the
megaflow, so the xlate will still translate the commit action into zone=5,
and the new traffic will still commit to CT as zone=5, not zone=15,
resulting in taffic drops and other issues.
Just like OVS set-field convention, if a field X is set by Y
(Y is a variable not an Imm), we should also mask Y as a match
in the generated megaflow. An exception is that if the zone-id is
set by the field that is included in the frozen state (i.e. regs) and this
upcall is a resume of a thawed xlate, the un-wildcarding can be skipped,
as the recirc_id is a hash of the values in these fields, and it will change
following the changes of these fields. When the recirc_id changes,
all megaflows with the old recirc id will be invalid later.
Fixes: 07659514c3 ("Add support for connection tracking.")
Reported-by: Sai Su <susai.ss@bytedance.com>
Signed-off-by: Peng He <hepeng.0320@bytedance.com>
Acked-by: Mark D. Gray <mark.d.gray@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Diffstat (limited to 'ofproto/ofproto-dpif-xlate.c')
-rw-r--r-- | ofproto/ofproto-dpif-xlate.c | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 8723cb4e8..9d336bc6a 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -6199,11 +6199,32 @@ static void compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, bool is_last_action) { - ovs_u128 old_ct_label_mask = ctx->wc->masks.ct_label; - uint32_t old_ct_mark_mask = ctx->wc->masks.ct_mark; - size_t ct_offset; uint16_t zone; + if (ofc->zone_src.field) { + union mf_subvalue value; + memset(&value, 0xff, sizeof(value)); + + zone = mf_get_subfield(&ofc->zone_src, &ctx->xin->flow); + if (ctx->xin->frozen_state) { + /* If the upcall is a resume of a recirculation, we only need to + * unwildcard the fields that are not in the frozen_metadata, as + * when the rules update, OVS will generate a new recirc_id, + * which will invalidate the megaflow with old the recirc_id. + */ + if (!mf_is_frozen_metadata(ofc->zone_src.field)) { + mf_write_subfield_flow(&ofc->zone_src, &value, + &ctx->wc->masks); + } + } else { + mf_write_subfield_flow(&ofc->zone_src, &value, &ctx->wc->masks); + } + } else { + zone = ofc->zone_imm; + } + size_t ct_offset; + ovs_u128 old_ct_label_mask = ctx->wc->masks.ct_label; + uint32_t old_ct_mark_mask = ctx->wc->masks.ct_mark; /* Ensure that any prior actions are applied before composing the new * conntrack action. */ xlate_commit_actions(ctx); @@ -6215,11 +6236,6 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, do_xlate_actions(ofc->actions, ofpact_ct_get_action_len(ofc), ctx, is_last_action, false); - if (ofc->zone_src.field) { - zone = mf_get_subfield(&ofc->zone_src, &ctx->xin->flow); - } else { - zone = ofc->zone_imm; - } ct_offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_CT); if (ofc->flags & NX_CT_F_COMMIT) { |