diff -Nru openvswitch-2.17.0/debian/changelog openvswitch-2.17.0/debian/changelog --- openvswitch-2.17.0/debian/changelog 2022-02-18 10:20:30.000000000 +0000 +++ openvswitch-2.17.0/debian/changelog 2022-05-18 12:25:51.000000000 +0000 @@ -1,3 +1,10 @@ +openvswitch (2.17.0-0ubuntu1.0) jammy; urgency=medium + + * d/p/lp-1967856-ct.patch: Fix conntrack related hairpin traffic issue + (LP: #1967856). + + -- Frode Nordahl Wed, 18 May 2022 12:25:51 +0000 + openvswitch (2.17.0-0ubuntu1) jammy; urgency=medium * New upstream release. diff -Nru openvswitch-2.17.0/debian/patches/lp-1967856-ct.patch openvswitch-2.17.0/debian/patches/lp-1967856-ct.patch --- openvswitch-2.17.0/debian/patches/lp-1967856-ct.patch 1970-01-01 00:00:00.000000000 +0000 +++ openvswitch-2.17.0/debian/patches/lp-1967856-ct.patch 2022-05-18 12:24:59.000000000 +0000 @@ -0,0 +1,257 @@ +Index: openvswitch-2.17.0/include/openvswitch/ofp-packet.h +=================================================================== +--- openvswitch-2.17.0.orig/include/openvswitch/ofp-packet.h ++++ openvswitch-2.17.0/include/openvswitch/ofp-packet.h +@@ -133,6 +133,9 @@ struct ofputil_packet_in_private { + /* NXCPT_CONNTRACKED. */ + bool conntracked; + ++ /* NXCPT_PENDING_CT_CLEAR. */ ++ bool pending_ct_clear; ++ + /* NXCPT_ACTIONS. */ + struct ofpact *actions; + size_t actions_len; +Index: openvswitch-2.17.0/lib/ofp-packet.c +=================================================================== +--- openvswitch-2.17.0.orig/lib/ofp-packet.c ++++ openvswitch-2.17.0/lib/ofp-packet.c +@@ -421,6 +421,7 @@ enum nx_continuation_prop_type { + NXCPT_ACTIONS, + NXCPT_ACTION_SET, + NXCPT_ODP_PORT, ++ NXCPT_PENDING_CT_CLEAR, + }; + + /* Only NXT_PACKET_IN2 (not NXT_RESUME) should include NXCPT_USERDATA, so this +@@ -456,6 +457,10 @@ ofputil_put_packet_in_private(const stru + ofpprop_put_flag(msg, NXCPT_CONNTRACKED); + } + ++ if (pin->pending_ct_clear) { ++ ofpprop_put_flag(msg, NXCPT_PENDING_CT_CLEAR); ++ } ++ + if (pin->actions_len) { + /* Divide 'pin->actions' into groups that begins with an + * unroll_xlate action. For each group, emit a NXCPT_TABLE_ID and +@@ -859,6 +864,10 @@ ofputil_decode_packet_in_private(const s + pin->conntracked = true; + break; + ++ case NXCPT_PENDING_CT_CLEAR: ++ pin->pending_ct_clear = true; ++ break; ++ + case NXCPT_TABLE_ID: + error = ofpprop_parse_u8(&payload, &table_id); + break; +Index: openvswitch-2.17.0/ofproto/ofproto-dpif-rid.h +=================================================================== +--- openvswitch-2.17.0.orig/ofproto/ofproto-dpif-rid.h ++++ openvswitch-2.17.0/ofproto/ofproto-dpif-rid.h +@@ -153,6 +153,7 @@ struct frozen_state { + size_t stack_size; + mirror_mask_t mirrors; /* Mirrors already output. */ + bool conntracked; /* Conntrack occurred prior to freeze. */ ++ bool pending_ct_clear; /* ct_clear required before the next ct(). */ + bool was_mpls; /* MPLS packet */ + struct uuid xport_uuid; /* UUID of 1st port packet received on. */ + +Index: openvswitch-2.17.0/ofproto/ofproto-dpif-xlate.c +=================================================================== +--- openvswitch-2.17.0.orig/ofproto/ofproto-dpif-xlate.c ++++ openvswitch-2.17.0/ofproto/ofproto-dpif-xlate.c +@@ -396,6 +396,10 @@ struct xlate_ctx { + * state from the datapath should be honored after thawing. */ + bool conntracked; + ++ /* True if datapath ct_clear action has to be performed before the next ++ * ct() action. */ ++ bool pending_ct_clear; ++ + /* Pointer to an embedded NAT action in a conntrack action, or NULL. */ + struct ofpact_nat *ct_nat_action; + +@@ -3831,6 +3835,7 @@ patch_port_output(struct xlate_ctx *ctx, + struct flow old_flow = ctx->xin->flow; + struct flow_tnl old_flow_tnl_wc = ctx->wc->masks.tunnel; + bool old_conntrack = ctx->conntracked; ++ bool old_ct_clear = ctx->pending_ct_clear; + bool old_was_mpls = ctx->was_mpls; + ovs_version_t old_version = ctx->xin->tables_version; + struct ofpbuf old_stack = ctx->stack; +@@ -3850,6 +3855,12 @@ patch_port_output(struct xlate_ctx *ctx, + ctx->wc->masks.tunnel.metadata.tab = flow->tunnel.metadata.tab; + memset(flow->regs, 0, sizeof flow->regs); + flow->actset_output = OFPP_UNSET; ++ if (ctx->conntracked) { ++ /* Patch ports do not carry conntrack information, so any conntrack ++ * state must be removed from the packet before processing ct actions ++ * in another bridge. */ ++ ctx->pending_ct_clear = true; ++ } + clear_conntrack(ctx); + ctx->xin->trace = xlate_report(ctx, OFT_BRIDGE, "bridge(\"%s\")", + out_dev->xbridge->name); +@@ -3918,6 +3929,7 @@ patch_port_output(struct xlate_ctx *ctx, + /* The out bridge's conntrack execution should have no effect on the + * original bridge. */ + ctx->conntracked = old_conntrack; ++ ctx->pending_ct_clear = old_ct_clear; + + /* The fact that the out bridge exits (for any reason) does not mean + * that the original bridge should exit. Specifically, if the out +@@ -4899,6 +4911,7 @@ xlate_controller_action(struct xlate_ctx + .stack_size = ctx->stack.size, + .mirrors = ctx->mirrors, + .conntracked = ctx->conntracked, ++ .pending_ct_clear = ctx->pending_ct_clear, + .was_mpls = ctx->was_mpls, + .ofpacts = NULL, + .ofpacts_len = 0, +@@ -4974,6 +4987,7 @@ finish_freezing__(struct xlate_ctx *ctx, + .stack_size = ctx->stack.size, + .mirrors = ctx->mirrors, + .conntracked = ctx->conntracked, ++ .pending_ct_clear = ctx->pending_ct_clear, + .was_mpls = ctx->was_mpls, + .xport_uuid = ctx->xin->xport_uuid, + .ofpacts = ctx->frozen_actions.data, +@@ -5804,6 +5818,7 @@ clone_xlate_actions(const struct ofpact + struct flow old_base = ctx->base_flow; + bool old_was_mpls = ctx->was_mpls; + bool old_conntracked = ctx->conntracked; ++ bool old_ct_clear = ctx->pending_ct_clear; + + /* The actions are not reversible, a datapath clone action is + * required to encode the translation. Select the clone action +@@ -5852,6 +5867,7 @@ dp_clone_done: + /* The clone's conntrack execution should have no effect on the original + * packet. */ + ctx->conntracked = old_conntracked; ++ ctx->pending_ct_clear = old_ct_clear; + + /* Popping MPLS from the clone should have no effect on the original + * packet. */ +@@ -6098,6 +6114,18 @@ freeze_unroll_actions(const struct ofpac + } + + static void ++compose_ct_clear_action(struct xlate_ctx *ctx) ++{ ++ clear_conntrack(ctx); ++ ctx->pending_ct_clear = false; ++ /* This action originally existed without dpif support. So to preserve ++ * compatibility, only append it if the dpif supports it. */ ++ if (ctx->xbridge->support.ct_clear) { ++ nl_msg_put_flag(ctx->odp_actions, OVS_ACTION_ATTR_CT_CLEAR); ++ } ++} ++ ++static void + put_ct_mark(const struct flow *flow, struct ofpbuf *odp_actions, + struct flow_wildcards *wc) + { +@@ -6305,25 +6333,21 @@ compose_conntrack_action(struct xlate_ct + compose_recirculate_and_fork(ctx, ofc->recirc_table, zone); + } + ++ /* Datapath will update the conntrack state for the packet, but ++ * NXAST_CT action must always put the packet into an untracked ++ * state. Execution continues in the current table without ++ * recirculation, hence conntrack state should not be available. ++ * We'll ask the datapath to clear what OVS_ACTION_ATTR_CT might ++ * have changed in the packet metadata before the next ct() action. */ ++ ctx->pending_ct_clear = true; ++ + ctx->ct_nat_action = NULL; + + /* The ct_* fields are only available in the scope of the 'recirc_table' + * call chain. */ +- flow_clear_conntrack(&ctx->xin->flow); + xlate_report(ctx, OFT_DETAIL, "Sets the packet to an untracked state, " + "and clears all the conntrack fields."); +- ctx->conntracked = false; +-} +- +-static void +-compose_ct_clear_action(struct xlate_ctx *ctx) +-{ + clear_conntrack(ctx); +- /* This action originally existed without dpif support. So to preserve +- * compatibility, only append it if the dpif supports it. */ +- if (ctx->xbridge->support.ct_clear) { +- nl_msg_put_flag(ctx->odp_actions, OVS_ACTION_ATTR_CT_CLEAR); +- } + } + + /* check_pkt_larger action checks the packet length and stores the +@@ -6384,6 +6408,7 @@ xlate_check_pkt_larger(struct xlate_ctx + struct flow old_base = ctx->base_flow; + bool old_was_mpls = ctx->was_mpls; + bool old_conntracked = ctx->conntracked; ++ bool old_ct_clear = ctx->pending_ct_clear; + + size_t offset = nl_msg_start_nested(ctx->odp_actions, + OVS_ACTION_ATTR_CHECK_PKT_LEN); +@@ -6405,6 +6430,7 @@ xlate_check_pkt_larger(struct xlate_ctx + ctx->base_flow = old_base; + ctx->was_mpls = old_was_mpls; + ctx->conntracked = old_conntracked; ++ ctx->pending_ct_clear = old_ct_clear; + ctx->xin->flow = old_flow; + + /* If the flow translation for the IF_GREATER case requires freezing, +@@ -6435,6 +6461,7 @@ xlate_check_pkt_larger(struct xlate_ctx + ctx->base_flow = old_base; + ctx->was_mpls = old_was_mpls; + ctx->conntracked = old_conntracked; ++ ctx->pending_ct_clear = old_ct_clear; + ctx->xin->flow = old_flow; + ctx->exit = old_exit; + } +@@ -7285,11 +7312,17 @@ do_xlate_actions(const struct ofpact *of + } + + case OFPACT_CT: ++ if (ctx->pending_ct_clear) { ++ /* Previous ct() action might have made some changes but ++ * the packet must be untracked. Clearing the state before ++ * executing a new ct() action. */ ++ compose_ct_clear_action(ctx); ++ } + compose_conntrack_action(ctx, ofpact_get_CT(a), last); + break; + + case OFPACT_CT_CLEAR: +- if (ctx->conntracked) { ++ if (ctx->conntracked || ctx->pending_ct_clear) { + compose_ct_clear_action(ctx); + } + break; +@@ -7679,6 +7712,7 @@ xlate_actions(struct xlate_in *xin, stru + + .was_mpls = false, + .conntracked = false, ++ .pending_ct_clear = false, + + .ct_nat_action = NULL, + +@@ -7743,6 +7777,8 @@ xlate_actions(struct xlate_in *xin, stru + clear_conntrack(&ctx); + } + ++ ctx.pending_ct_clear = state->pending_ct_clear; ++ + /* Restore pipeline metadata. May change flow's in_port and other + * metadata to the values that existed when freezing was triggered. */ + frozen_metadata_to_flow(&ctx.xbridge->ofproto->up, +@@ -8082,6 +8118,7 @@ xlate_resume(struct ofproto_dpif *ofprot + .stack_size = pin->stack_size, + .mirrors = pin->mirrors, + .conntracked = pin->conntracked, ++ .pending_ct_clear = pin->pending_ct_clear, + .xport_uuid = UUID_ZERO, + + /* When there are no actions, xlate_actions() will search the flow diff -Nru openvswitch-2.17.0/debian/patches/series openvswitch-2.17.0/debian/patches/series --- openvswitch-2.17.0/debian/patches/series 2022-02-18 08:33:39.000000000 +0000 +++ openvswitch-2.17.0/debian/patches/series 2022-05-18 12:24:54.000000000 +0000 @@ -1 +1,2 @@ ovs-ctl-ipsec.patch +lp-1967856-ct.patch