When offloading a flow via the default nft flowtable path, append a FLOW_ACTION_CT_METADATA action if the flow is associated with a conntrack entry. We do this in both IPv4 and IPv6 route action builders, after NAT mangles and before redirect. This mirrors net/sched/act_ct.c’s tcf_ct_flow_table_add_action_meta() so drivers that already parse FLOW_ACTION_CT_METADATA from TC offloads can reuse the same logic for nft flowtables. Signed-off-by: Elad Yifee --- net/netfilter/nf_flow_table_offload.c | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c index e06bc36f49fe..bccae4052319 100644 --- a/net/netfilter/nf_flow_table_offload.c +++ b/net/netfilter/nf_flow_table_offload.c @@ -12,6 +12,7 @@ #include #include #include +#include static struct workqueue_struct *nf_flow_offload_add_wq; static struct workqueue_struct *nf_flow_offload_del_wq; @@ -679,6 +680,41 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow, return 0; } +static void flow_offload_add_ct_metadata(const struct flow_offload *flow, + enum flow_offload_tuple_dir dir, + struct nf_flow_rule *flow_rule) +{ + struct nf_conn *ct = flow->ct; + struct flow_action_entry *entry; +#if IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) + u32 *dst_labels; + struct nf_conn_labels *labels; +#endif + + if (!ct) + return; + + entry = flow_action_entry_next(flow_rule); + entry->id = FLOW_ACTION_CT_METADATA; + +#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) + entry->ct_metadata.mark = READ_ONCE(ct->mark); +#endif + + entry->ct_metadata.orig_dir = (dir == FLOW_OFFLOAD_DIR_ORIGINAL); + +#if IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) + dst_labels = entry->ct_metadata.labels; + labels = nf_ct_labels_find(ct); + if (labels) + memcpy(dst_labels, labels->bits, NF_CT_LABELS_MAX_SIZE); + else + memset(dst_labels, 0, NF_CT_LABELS_MAX_SIZE); +#else + memset(entry->ct_metadata.labels, 0, NF_CT_LABELS_MAX_SIZE); +#endif +} + int nf_flow_rule_route_ipv4(struct net *net, struct flow_offload *flow, enum flow_offload_tuple_dir dir, struct nf_flow_rule *flow_rule) @@ -698,6 +734,7 @@ int nf_flow_rule_route_ipv4(struct net *net, struct flow_offload *flow, test_bit(NF_FLOW_DNAT, &flow->flags)) flow_offload_ipv4_checksum(net, flow, flow_rule); + flow_offload_add_ct_metadata(flow, dir, flow_rule); flow_offload_redirect(net, flow, dir, flow_rule); return 0; @@ -720,6 +757,7 @@ int nf_flow_rule_route_ipv6(struct net *net, struct flow_offload *flow, flow_offload_port_dnat(net, flow, dir, flow_rule); } + flow_offload_add_ct_metadata(flow, dir, flow_rule); flow_offload_redirect(net, flow, dir, flow_rule); return 0; -- 2.48.1