The next patch offloads TCP flows without a reply in the original direction only. Keep the reply direction of such a flow on the classic path until the connection is assured, then offload it too, as act_ct does for UDP. The XDP flowtable lookup does not return that reply tuple either.
Assisted-by: Claude:claude-opus-5 Signed-off-by: Julius Bairaktaris <[email protected]> --- net/netfilter/nf_flow_table_bpf.c | 4 ++++ net/netfilter/nf_flow_table_ip.c | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/net/netfilter/nf_flow_table_bpf.c b/net/netfilter/nf_flow_table_bpf.c index cbd5b97a6329..7070bc600db1 100644 --- a/net/netfilter/nf_flow_table_bpf.c +++ b/net/netfilter/nf_flow_table_bpf.c @@ -50,6 +50,10 @@ bpf_xdp_flow_tuple_lookup(struct net_device *dev, nf_flow = container_of(tuplehash, struct flow_offload, tuplehash[tuplehash->tuple.dir]); + if (tuplehash->tuple.dir == FLOW_OFFLOAD_DIR_REPLY && + !test_bit(NF_FLOW_HW_BIDIRECTIONAL, &nf_flow->flags)) + return ERR_PTR(-ENOENT); + flow_offload_refresh(nf_flow_table, nf_flow, false); return tuplehash; diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c index c8c29a9a1684..289fe6c9e4f5 100644 --- a/net/netfilter/nf_flow_table_ip.c +++ b/net/netfilter/nf_flow_table_ip.c @@ -465,6 +465,26 @@ nf_flow_offload_lookup(struct nf_flowtable_ctx *ctx, return flow_offload_lookup(flow_table, &tuple); } +/* The reply direction of a flow offloaded in one direction only stays on the + * classic path so that conntrack sees it. Once the connection is assured, that + * direction is offloaded too. + */ +static bool nf_flow_reply_unoffloaded(struct nf_flowtable *flow_table, + struct flow_offload *flow, + enum flow_offload_tuple_dir dir) +{ + if (dir != FLOW_OFFLOAD_DIR_REPLY || + test_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags)) + return false; + + if (test_bit(IPS_ASSURED_BIT, &flow->ct->status)) { + set_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags); + flow_offload_refresh(flow_table, flow, true); + } + + return true; +} + static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx, struct nf_flowtable *flow_table, struct flow_offload_tuple_rhash *tuplehash, @@ -478,6 +498,9 @@ static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx, dir = tuplehash->tuple.dir; flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); + if (nf_flow_reply_unoffloaded(flow_table, flow, dir)) + return 0; + mtu = flow->tuplehash[dir].tuple.mtu + ctx->offset; if (flow->tuplehash[!dir].tuple.tun_num) mtu -= sizeof(*iph); @@ -1074,6 +1097,9 @@ static int nf_flow_offload_ipv6_forward(struct nf_flowtable_ctx *ctx, dir = tuplehash->tuple.dir; flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); + if (nf_flow_reply_unoffloaded(flow_table, flow, dir)) + return 0; + mtu = flow->tuplehash[dir].tuple.mtu + ctx->offset; if (flow->tuplehash[!dir].tuple.tun_num) mtu -= sizeof(*ip6h); -- 2.53.0
