{"id":2215612,"url":"http://patchwork.ozlabs.org/api/patches/2215612/?format=json","web_url":"http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260324204016.2089193-2-anzaki@gmail.com/","project":{"id":26,"url":"http://patchwork.ozlabs.org/api/projects/26/?format=json","name":"Netfilter Development","link_name":"netfilter-devel","list_id":"netfilter-devel.vger.kernel.org","list_email":"netfilter-devel@vger.kernel.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260324204016.2089193-2-anzaki@gmail.com>","list_archive_url":null,"date":"2026-03-24T20:40:15","name":"[nf-next,v2,1/2] netfilter: flowtable: update netdev stats with HW_OFFLOAD flows","commit_ref":null,"pull_url":null,"state":"needs-review-ack","archived":false,"hash":"17705f54f9f4096f92b120ca6c66febdb47a0146","submitter":{"id":77450,"url":"http://patchwork.ozlabs.org/api/people/77450/?format=json","name":"Ahmed Zaki","email":"anzaki@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260324204016.2089193-2-anzaki@gmail.com/mbox/","series":[{"id":497346,"url":"http://patchwork.ozlabs.org/api/series/497346/?format=json","web_url":"http://patchwork.ozlabs.org/project/netfilter-devel/list/?series=497346","date":"2026-03-24T20:40:16","name":"Update (DSA) netdev stats with offloaded flows","version":2,"mbox":"http://patchwork.ozlabs.org/series/497346/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2215612/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2215612/checks/","tags":{},"related":[],"headers":{"Return-Path":"\n <netfilter-devel+bounces-11387-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","netfilter-devel@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=iAKtSEfZ;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c04:e001:36c::12fc:5321; helo=tor.lore.kernel.org;\n envelope-from=netfilter-devel+bounces-11387-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"iAKtSEfZ\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.128.48","smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.com"],"Received":["from tor.lore.kernel.org (tor.lore.kernel.org\n [IPv6:2600:3c04:e001:36c::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fgMSn3gWPz1xy1\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 25 Mar 2026 07:43:37 +1100 (AEDT)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id EEEBC308C836\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 24 Mar 2026 20:41:36 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id AB08D35836A;\n\tTue, 24 Mar 2026 20:41:33 +0000 (UTC)","from mail-wm1-f48.google.com (mail-wm1-f48.google.com\n [209.85.128.48])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id A063F33B6DB\n\tfor <netfilter-devel@vger.kernel.org>; Tue, 24 Mar 2026 20:41:31 +0000 (UTC)","by mail-wm1-f48.google.com with SMTP id\n 5b1f17b1804b1-486507134e4so21093265e9.0\n        for <netfilter-devel@vger.kernel.org>;\n Tue, 24 Mar 2026 13:41:31 -0700 (PDT)","from azaki-desk1.. ([41.234.201.118])\n        by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-48716658352sm3686825e9.13.2026.03.24.13.41.24\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Tue, 24 Mar 2026 13:41:25 -0700 (PDT)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1774384893; cv=none;\n b=l6DbsuLMS6agxZrQs5+IEoSAvwTacMTRFBc5ogtWFeI0niuQmJxvIkzCki7PKalUeyvg/ekNWBhdqqhrAs1BZ7Vwnc6CdgblX0celQN3WbNxmui6PZOdIAM9xbjpUdInNxaOmRflNLhjzi2JGoObWBa+ViJbf/lk3byhVp3drXs=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1774384893; c=relaxed/simple;\n\tbh=OMzMv0TSgnhZtLvwhP+BHffFyvt+TSPyAeE/6RqIn8A=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=MYia12zNEIAJ5uLmFcXYORNrB3km/9W2kp6DEqEqAbBiFf87emwxcYoGDfNXtmltxaKvv91d/D5AOxvM65Hn0mR9ZE7ueHOvsUFINdGetF8d71y6A1kfpTvGG6MoLG7D3okc5WnVcuJ78V9VuQHewxoxFa7+3Vta2MrFg1vrdFA=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=iAKtSEfZ; arc=none smtp.client-ip=209.85.128.48","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=gmail.com; s=20251104; t=1774384887; x=1774989687;\n darn=vger.kernel.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n         :message-id:reply-to;\n        bh=D0C5qZvIKcbCB9gIop4y1SIVtOCb4Lm6XlWELeubUrQ=;\n        b=iAKtSEfZS2/Or6UT5n+zWYVaGk0wFOcjtJF3ZUI3b0H13o8I5B9nQsADOUJ2dxc30U\n         mUeRNaV4Acp0+Ng/8Q6vjIiBk81zBdsg3ag9LhtHsK/mQzYrxEO+C2lKTgzVcSf0Vsos\n         s9lSr+qtoKWRT/M2yzQQ0Ra4eVSoz2MpfLGatyDKotQ06ZSRAimZrDk0xQK2Z2jWVWZv\n         RQKQE5L+LVJNpTT9dqY5FgQ1HRrtb+6LgN5PmdERvArgYlJhNvxswkDYB0iADDq4pssf\n         csStCGtImcViBTAauFGJKYR+By+VWli50k2+/J1T2FJGtcIgu9VDAuAxNYJsGR08KAbP\n         f2fA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20251104; t=1774384887; x=1774989687;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n         :to:cc:subject:date:message-id:reply-to;\n        bh=D0C5qZvIKcbCB9gIop4y1SIVtOCb4Lm6XlWELeubUrQ=;\n        b=su+53+IhZLH+2OBtzAftElv7ggxSRTsL0VUoemAiuS+vXQfudfPApaOOv6YDNDxTkA\n         NTZRliv9eUHWhVFBIarOsvAXNFyFzGmLnM/up1CPw/iTAKnbfMx5QsFzFoGV7q8gT/ui\n         rkfNbdm0cR02Iq1lErJdAdyidU1Win3APTQihV7N6+2jkhKw8igWP7Z48DfJWONwKhjr\n         0YjYJ9DQE7NiTjP5QpaqFpx1QihfWewn+J0CuXGI5tE3BCu8QRu7PpV+RhuTCc/HM+LK\n         qTOPVGthY9cUyPQSUrqpGqxeZrYj3hv4ibm52uYTv8PtUGHfm086d1Y+FYcG4LkyJAv1\n         wSlA==","X-Gm-Message-State":"AOJu0Yz4Q3K6vwmFfjdU6p8OHaddZhrCmznJKMS9hEsdHUZ9YEjGjZnt\n\tO9GjB4JuVL6NYDUv/Zngsw+aMq08/+ci1vnw5spHoQ4DPwHFo/LAfqKgojb9b0vRPwxoCw==","X-Gm-Gg":"ATEYQzzzwSmx0cVGKR77yxFu0TMAyK+bptpZo+1LFHDF8+hFx2+IqvQ246MvTtnxwyA\n\t9U4fKr8R5c6o5mf8jTE5EgWNcgJgVCgKUD+rwx+ayfPqYjPOcvZNvw1HCWRx9ESMRTa4EyNr6nt\n\tR1PfBVkP3HUnqG5gxA2UApQ/2AXYHdAi6jB6PUL8OmZQ0ucChNHu/qVqa6h9iyT9tDzifep+NrN\n\tlDaIZIJ/OdoJLJb0ZTRvPe2Ic5yCmSCJMo11V5thiOz1VWa+Vn/IVXa9BmkHn5uEYaZztq6qWL8\n\tqD68CSAhrM2urnEGgz8/RD+2msF1XxmQrSjhhIDgr3Tk4jtKqa1+WOTc7f7G0v/PjzwO60YVts4\n\tjcSevzIB1LObvBjWr5gFCAJd7XhSr5f2eAbxFfBsKNajMu53yepLkdIkebQYear02fOrdZ5eq/g\n\tCOXIcYH8smFM7bvbHiTwH6","X-Received":"by 2002:a05:600c:4685:b0:486:5f71:5829 with SMTP id\n 5b1f17b1804b1-48715fc3870mr17265075e9.5.1774384886440;\n        Tue, 24 Mar 2026 13:41:26 -0700 (PDT)","From":"Ahmed Zaki <anzaki@gmail.com>","To":"netfilter-devel@vger.kernel.org,\n\tandrew@lunn.ch,\n\tolteanv@gmail.com,\n\tpablo@netfilter.org,\n\tfw@strlen.de,\n\tkuba@kernel.org,\n\tpabeni@redhat.com,\n\tedumazet@google.com","Cc":"coreteam@netfilter.org,\n\tnetdev@vger.kernel.org","Subject":"[PATCH nf-next v2 1/2] netfilter: flowtable: update netdev stats with\n HW_OFFLOAD flows","Date":"Tue, 24 Mar 2026 14:40:15 -0600","Message-ID":"<20260324204016.2089193-2-anzaki@gmail.com>","X-Mailer":"git-send-email 2.43.0","In-Reply-To":"<20260324204016.2089193-1-anzaki@gmail.com>","References":"<20260324204016.2089193-1-anzaki@gmail.com>","Precedence":"bulk","X-Mailing-List":"netfilter-devel@vger.kernel.org","List-Id":"<netfilter-devel.vger.kernel.org>","List-Subscribe":"<mailto:netfilter-devel+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:netfilter-devel+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit"},"content":"Some drivers (notably DSA) delegate the nft flowtable HW_OFFLOAD flows\nto a parent driver. While the parent driver is able to report the\noffloaded traffic stats directly from the HW, the delegating driver\ndoes not report the stats. This fails SNMP-based monitoring tools that\nrely on netdev stats to report the network traffic.\n\nAdd a new struct pcpu_sw_netstats \"fstats\" to net_device that gets\nallocated only if the new flag \"flow_offload_via_parent\" is set by the\ndriver. The new stats are lazily allocated by the nft flow offloading\ncode when the first flow is offloaded. The stats are updated periodically\nin flow_offload_work_stats() and also once in flow_offload_work_del()\nbefore the flow is deleted. For this, flow_offload_work_del() had to\nbe moved below flow_offload_tuple_stats().\n\nSigned-off-by: Ahmed Zaki <anzaki@gmail.com>\n---\n include/linux/netdevice.h             | 45 ++++++++++++\n net/core/dev.c                        |  8 +++\n net/netfilter/nf_flow_table_offload.c | 98 +++++++++++++++++++++++++--\n 3 files changed, 145 insertions(+), 6 deletions(-)","diff":"diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h\nindex 67e25f6d15a4..647758f78213 100644\n--- a/include/linux/netdevice.h\n+++ b/include/linux/netdevice.h\n@@ -1840,6 +1840,11 @@ enum netdev_reg_state {\n  *\t@stats:\t\tStatistics struct, which was left as a legacy, use\n  *\t\t\trtnl_link_stats64 instead\n  *\n+ *\t@fstats:\tHW offloaded flow statistics: RX/TX packets,\n+ *\t\t\tRX/TX bytes. Lazily allocated by the flow offload\n+ *\t\t\tpath on the first offloaded flow for devices that\n+ *\t\t\tset @flow_offload_via_parent. Freed by free_netdev().\n+ *\n  *\t@core_stats:\tcore networking counters,\n  *\t\t\tdo not use this in drivers\n  *\t@carrier_up_count:\tNumber of times the carrier has been up\n@@ -2048,6 +2053,12 @@ enum netdev_reg_state {\n  *\t@change_proto_down: device supports setting carrier via IFLA_PROTO_DOWN\n  *\t@netns_immutable: interface can't change network namespaces\n  *\t@fcoe_mtu:\tdevice supports maximum FCoE MTU, 2158 bytes\n+ *\t@flow_offload_via_parent: device delegates nft flowtable hardware\n+ *\t\t\t\t  offload to a parent/conduit device (e.g. DSA\n+ *\t\t\t\t  user ports delegate to their conduit MAC).\n+ *\t\t\t\t  The parent's HW count the offloaded traffic\n+ *\t\t\t\t  but this device's sw netstats path does not.\n+ *\t\t\t\t  @fstats is allocated to fill that gap.\n  *\n  *\t@net_notifier_list:\tList of per-net netdev notifier block\n  *\t\t\t\tthat follow this device when it is moved\n@@ -2233,6 +2244,7 @@ struct net_device {\n \n \tstruct net_device_stats\tstats; /* not used by modern drivers */\n \n+\tstruct pcpu_sw_netstats __percpu *fstats;\n \tstruct net_device_core_stats __percpu *core_stats;\n \n \t/* Stats to monitor link on/off, flapping */\n@@ -2463,6 +2475,7 @@ struct net_device {\n \tunsigned long\t\tchange_proto_down:1;\n \tunsigned long\t\tnetns_immutable:1;\n \tunsigned long\t\tfcoe_mtu:1;\n+\tunsigned long\t\tflow_offload_via_parent:1;\n \n \tstruct list_head\tnet_notifier_list;\n \n@@ -2992,6 +3005,38 @@ struct pcpu_lstats {\n \n void dev_lstats_read(struct net_device *dev, u64 *packets, u64 *bytes);\n \n+static inline void dev_fstats_rx_add(struct net_device *dev,\n+\t\t\t\t     unsigned int packets,\n+\t\t\t\t     unsigned int len)\n+{\n+\tstruct pcpu_sw_netstats *fstats;\n+\n+\tif (!dev->fstats)\n+\t\treturn;\n+\n+\tfstats = this_cpu_ptr(dev->fstats);\n+\tu64_stats_update_begin(&fstats->syncp);\n+\tu64_stats_add(&fstats->rx_bytes, len);\n+\tu64_stats_add(&fstats->rx_packets, packets);\n+\tu64_stats_update_end(&fstats->syncp);\n+}\n+\n+static inline void dev_fstats_tx_add(struct net_device *dev,\n+\t\t\t\t     unsigned int packets,\n+\t\t\t\t     unsigned int len)\n+{\n+\tstruct pcpu_sw_netstats *fstats;\n+\n+\tif (!dev->fstats)\n+\t\treturn;\n+\n+\tfstats = this_cpu_ptr(dev->fstats);\n+\tu64_stats_update_begin(&fstats->syncp);\n+\tu64_stats_add(&fstats->tx_bytes, len);\n+\tu64_stats_add(&fstats->tx_packets, packets);\n+\tu64_stats_update_end(&fstats->syncp);\n+}\n+\n static inline void dev_sw_netstats_rx_add(struct net_device *dev, unsigned int len)\n {\n \tstruct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);\ndiff --git a/net/core/dev.c b/net/core/dev.c\nindex f48dc299e4b2..07fb315ad42c 100644\n--- a/net/core/dev.c\n+++ b/net/core/dev.c\n@@ -11865,6 +11865,7 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,\n {\n \tconst struct net_device_ops *ops = dev->netdev_ops;\n \tconst struct net_device_core_stats __percpu *p;\n+\tconst struct pcpu_sw_netstats __percpu *fstats;\n \n \t/*\n \t * IPv{4,6} and udp tunnels share common stat helpers and use\n@@ -11893,6 +11894,11 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,\n \t\tnetdev_stats_to_stats64(storage, &dev->stats);\n \t}\n \n+\t/* This READ_ONCE() pairs with cmpxchg in flow_offload_fstats_ensure() */\n+\tfstats = READ_ONCE(dev->fstats);\n+\tif (fstats)\n+\t\tdev_fetch_sw_netstats(storage, fstats);\n+\n \t/* This READ_ONCE() pairs with the write in netdev_core_stats_alloc() */\n \tp = READ_ONCE(dev->core_stats);\n \tif (p) {\n@@ -12212,6 +12218,8 @@ void free_netdev(struct net_device *dev)\n \tfree_percpu(dev->pcpu_refcnt);\n \tdev->pcpu_refcnt = NULL;\n #endif\n+\tfree_percpu(dev->fstats);\n+\tdev->fstats = NULL;\n \tfree_percpu(dev->core_stats);\n \tdev->core_stats = NULL;\n \tfree_percpu(dev->xdp_bulkq);\ndiff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c\nindex b2e4fb6fa011..fc1e67a79904 100644\n--- a/net/netfilter/nf_flow_table_offload.c\n+++ b/net/netfilter/nf_flow_table_offload.c\n@@ -925,13 +925,80 @@ static void flow_offload_work_add(struct flow_offload_work *offload)\n \tnf_flow_offload_destroy(flow_rule);\n }\n \n-static void flow_offload_work_del(struct flow_offload_work *offload)\n+static bool flow_offload_fstats_ensure(struct net_device *dev)\n {\n-\tclear_bit(IPS_HW_OFFLOAD_BIT, &offload->flow->ct->status);\n-\tflow_offload_tuple_del(offload, FLOW_OFFLOAD_DIR_ORIGINAL);\n-\tif (test_bit(NF_FLOW_HW_BIDIRECTIONAL, &offload->flow->flags))\n-\t\tflow_offload_tuple_del(offload, FLOW_OFFLOAD_DIR_REPLY);\n-\tset_bit(NF_FLOW_HW_DEAD, &offload->flow->flags);\n+\tstruct pcpu_sw_netstats __percpu *p;\n+\n+\tif (!dev->flow_offload_via_parent)\n+\t\treturn false;\n+\n+\t/* Pairs with cmpxchg() below. */\n+\tif (likely(READ_ONCE(dev->fstats)))\n+\t\treturn true;\n+\n+\tp = __netdev_alloc_pcpu_stats(struct pcpu_sw_netstats, GFP_ATOMIC);\n+\tif (!p)\n+\t\treturn false;\n+\n+\tif (cmpxchg(&dev->fstats, NULL, p))\n+\t\tfree_percpu(p);\t/* lost the race, discard and use winner's */\n+\n+\treturn true;\n+}\n+\n+static u32 flow_offload_egress_ifidx(const struct flow_offload_tuple *tuple)\n+{\n+\tswitch (tuple->xmit_type) {\n+\tcase FLOW_OFFLOAD_XMIT_NEIGH:\n+\t\treturn tuple->ifidx;\n+\tcase FLOW_OFFLOAD_XMIT_DIRECT:\n+\t\treturn tuple->out.ifidx;\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+}\n+\n+static void flow_offload_netdev_update(struct flow_offload_work *offload,\n+\t\t\t\t       struct flow_stats *stats)\n+{\n+\tconst struct flow_offload_tuple *tuple;\n+\tstruct net_device *indev, *outdev;\n+\tstruct net *net;\n+\n+\trcu_read_lock();\n+\tnet = read_pnet(&offload->flowtable->net);\n+\tif (stats[FLOW_OFFLOAD_DIR_ORIGINAL].pkts) {\n+\t\ttuple = &offload->flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple;\n+\t\tindev = dev_get_by_index_rcu(net, tuple->iifidx);\n+\t\tif (indev && flow_offload_fstats_ensure(indev))\n+\t\t\tdev_fstats_rx_add(indev,\n+\t\t\t\t\t  stats[FLOW_OFFLOAD_DIR_ORIGINAL].pkts,\n+\t\t\t\t\t  stats[FLOW_OFFLOAD_DIR_ORIGINAL].bytes);\n+\n+\t\toutdev = dev_get_by_index_rcu(net,\n+\t\t\t\t\t      flow_offload_egress_ifidx(tuple));\n+\t\tif (outdev && flow_offload_fstats_ensure(outdev))\n+\t\t\tdev_fstats_tx_add(outdev,\n+\t\t\t\t\t  stats[FLOW_OFFLOAD_DIR_ORIGINAL].pkts,\n+\t\t\t\t\t  stats[FLOW_OFFLOAD_DIR_ORIGINAL].bytes);\n+\t}\n+\n+\tif (stats[FLOW_OFFLOAD_DIR_REPLY].pkts) {\n+\t\ttuple = &offload->flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple;\n+\t\tindev = dev_get_by_index_rcu(net, tuple->iifidx);\n+\t\tif (indev && flow_offload_fstats_ensure(indev))\n+\t\t\tdev_fstats_rx_add(indev,\n+\t\t\t\t\t  stats[FLOW_OFFLOAD_DIR_REPLY].pkts,\n+\t\t\t\t\t  stats[FLOW_OFFLOAD_DIR_REPLY].bytes);\n+\n+\t\toutdev = dev_get_by_index_rcu(net,\n+\t\t\t\t\t      flow_offload_egress_ifidx(tuple));\n+\t\tif (outdev && flow_offload_fstats_ensure(outdev))\n+\t\t\tdev_fstats_tx_add(outdev,\n+\t\t\t\t\t  stats[FLOW_OFFLOAD_DIR_REPLY].pkts,\n+\t\t\t\t\t  stats[FLOW_OFFLOAD_DIR_REPLY].bytes);\n+\t}\n+\trcu_read_unlock();\n }\n \n static void flow_offload_tuple_stats(struct flow_offload_work *offload,\n@@ -968,6 +1035,25 @@ static void flow_offload_work_stats(struct flow_offload_work *offload)\n \t\t\t\t       FLOW_OFFLOAD_DIR_REPLY,\n \t\t\t\t       stats[1].pkts, stats[1].bytes);\n \t}\n+\n+\tflow_offload_netdev_update(offload, stats);\n+}\n+\n+static void flow_offload_work_del(struct flow_offload_work *offload)\n+{\n+\tstruct flow_stats stats[FLOW_OFFLOAD_DIR_MAX] = {};\n+\n+\tflow_offload_tuple_stats(offload, FLOW_OFFLOAD_DIR_ORIGINAL, &stats[0]);\n+\tif (test_bit(NF_FLOW_HW_BIDIRECTIONAL, &offload->flow->flags))\n+\t\tflow_offload_tuple_stats(offload, FLOW_OFFLOAD_DIR_REPLY,\n+\t\t\t\t\t &stats[1]);\n+\tflow_offload_netdev_update(offload, stats);\n+\n+\tclear_bit(IPS_HW_OFFLOAD_BIT, &offload->flow->ct->status);\n+\tflow_offload_tuple_del(offload, FLOW_OFFLOAD_DIR_ORIGINAL);\n+\tif (test_bit(NF_FLOW_HW_BIDIRECTIONAL, &offload->flow->flags))\n+\t\tflow_offload_tuple_del(offload, FLOW_OFFLOAD_DIR_REPLY);\n+\tset_bit(NF_FLOW_HW_DEAD, &offload->flow->flags);\n }\n \n static void flow_offload_work_handler(struct work_struct *work)\n","prefixes":["nf-next","v2","1/2"]}