* [PATCH nf-next 1/5] netfilter: flowtable: move path discovery infrastructure to its own file
2025-10-10 11:18 [PATCH nf-next 0/5] flowtable: consolidate xmit path Pablo Neira Ayuso
@ 2025-10-10 11:18 ` Pablo Neira Ayuso
2025-10-12 12:18 ` Florian Westphal
2025-10-10 11:18 ` [PATCH nf-next 2/5] netfilter: flowtable: consolidate xmit path Pablo Neira Ayuso
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2025-10-10 11:18 UTC (permalink / raw)
To: netfilter-devel
This file contains the path discovery that is run from the forward chain
for the packet offloading the flow into the flowtable. This consists
of a series of calls to dev_fill_forward_path() for each device stack.
More topologies may be supported in the future, so move this code to its
own file to separate it from the nftables flow_offload expression.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_flow_table.h | 6 +
net/netfilter/Makefile | 1 +
net/netfilter/nf_flow_table_path.c | 267 ++++++++++++++++++++++++++
net/netfilter/nft_flow_offload.c | 252 ------------------------
4 files changed, 274 insertions(+), 252 deletions(-)
create mode 100644 net/netfilter/nf_flow_table_path.c
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index c003cd194fa2..e9f72d2558e9 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -222,6 +222,12 @@ struct nf_flow_route {
struct flow_offload *flow_offload_alloc(struct nf_conn *ct);
void flow_offload_free(struct flow_offload *flow);
+struct nft_flowtable;
+struct nft_pktinfo;
+int nft_flow_route(const struct nft_pktinfo *pkt, const struct nf_conn *ct,
+ struct nf_flow_route *route, enum ip_conntrack_dir dir,
+ struct nft_flowtable *ft);
+
static inline int
nf_flow_table_offload_add_cb(struct nf_flowtable *flow_table,
flow_setup_cb_t *cb, void *cb_priv)
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index e43e20f529f8..6bfc250e474f 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -141,6 +141,7 @@ obj-$(CONFIG_NFT_FWD_NETDEV) += nft_fwd_netdev.o
# flow table infrastructure
obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_table.o
nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \
+ nf_flow_table_path.o \
nf_flow_table_offload.o nf_flow_table_xdp.o
nf_flow_table-$(CONFIG_NF_FLOW_TABLE_PROCFS) += nf_flow_table_procfs.o
ifeq ($(CONFIG_NF_FLOW_TABLE),m)
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
new file mode 100644
index 000000000000..159aa5c8da60
--- /dev/null
+++ b/net/netfilter/nf_flow_table_path.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/spinlock.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/ip.h>
+#include <net/inet_dscp.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables_core.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+#include <net/netfilter/nf_flow_table.h>
+
+static enum flow_offload_xmit_type nft_xmit_type(struct dst_entry *dst)
+{
+ if (dst_xfrm(dst))
+ return FLOW_OFFLOAD_XMIT_XFRM;
+
+ return FLOW_OFFLOAD_XMIT_NEIGH;
+}
+
+static void nft_default_forward_path(struct nf_flow_route *route,
+ struct dst_entry *dst_cache,
+ enum ip_conntrack_dir dir)
+{
+ route->tuple[!dir].in.ifindex = dst_cache->dev->ifindex;
+ route->tuple[dir].dst = dst_cache;
+ route->tuple[dir].xmit_type = nft_xmit_type(dst_cache);
+}
+
+static bool nft_is_valid_ether_device(const struct net_device *dev)
+{
+ if (!dev || (dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER ||
+ dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr))
+ return false;
+
+ return true;
+}
+
+static int nft_dev_fill_forward_path(const struct nf_flow_route *route,
+ const struct dst_entry *dst_cache,
+ const struct nf_conn *ct,
+ enum ip_conntrack_dir dir, u8 *ha,
+ struct net_device_path_stack *stack)
+{
+ const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
+ struct net_device *dev = dst_cache->dev;
+ struct neighbour *n;
+ u8 nud_state;
+
+ if (!nft_is_valid_ether_device(dev))
+ goto out;
+
+ n = dst_neigh_lookup(dst_cache, daddr);
+ if (!n)
+ return -1;
+
+ read_lock_bh(&n->lock);
+ nud_state = n->nud_state;
+ ether_addr_copy(ha, n->ha);
+ read_unlock_bh(&n->lock);
+ neigh_release(n);
+
+ if (!(nud_state & NUD_VALID))
+ return -1;
+
+out:
+ return dev_fill_forward_path(dev, ha, stack);
+}
+
+struct nft_forward_info {
+ const struct net_device *indev;
+ const struct net_device *outdev;
+ const struct net_device *hw_outdev;
+ struct id {
+ __u16 id;
+ __be16 proto;
+ } encap[NF_FLOW_TABLE_ENCAP_MAX];
+ u8 num_encaps;
+ u8 ingress_vlans;
+ u8 h_source[ETH_ALEN];
+ u8 h_dest[ETH_ALEN];
+ enum flow_offload_xmit_type xmit_type;
+};
+
+static void nft_dev_path_info(const struct net_device_path_stack *stack,
+ struct nft_forward_info *info,
+ unsigned char *ha, struct nf_flowtable *flowtable)
+{
+ const struct net_device_path *path;
+ int i;
+
+ memcpy(info->h_dest, ha, ETH_ALEN);
+
+ for (i = 0; i < stack->num_paths; i++) {
+ path = &stack->path[i];
+ switch (path->type) {
+ case DEV_PATH_ETHERNET:
+ case DEV_PATH_DSA:
+ case DEV_PATH_VLAN:
+ case DEV_PATH_PPPOE:
+ info->indev = path->dev;
+ if (is_zero_ether_addr(info->h_source))
+ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
+
+ if (path->type == DEV_PATH_ETHERNET)
+ break;
+ if (path->type == DEV_PATH_DSA) {
+ i = stack->num_paths;
+ break;
+ }
+
+ /* DEV_PATH_VLAN and DEV_PATH_PPPOE */
+ if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) {
+ info->indev = NULL;
+ break;
+ }
+ if (!info->outdev)
+ info->outdev = path->dev;
+ info->encap[info->num_encaps].id = path->encap.id;
+ info->encap[info->num_encaps].proto = path->encap.proto;
+ info->num_encaps++;
+ if (path->type == DEV_PATH_PPPOE)
+ memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
+ break;
+ case DEV_PATH_BRIDGE:
+ if (is_zero_ether_addr(info->h_source))
+ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
+
+ switch (path->bridge.vlan_mode) {
+ case DEV_PATH_BR_VLAN_UNTAG_HW:
+ info->ingress_vlans |= BIT(info->num_encaps - 1);
+ break;
+ case DEV_PATH_BR_VLAN_TAG:
+ info->encap[info->num_encaps].id = path->bridge.vlan_id;
+ info->encap[info->num_encaps].proto = path->bridge.vlan_proto;
+ info->num_encaps++;
+ break;
+ case DEV_PATH_BR_VLAN_UNTAG:
+ info->num_encaps--;
+ break;
+ case DEV_PATH_BR_VLAN_KEEP:
+ break;
+ }
+ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
+ break;
+ default:
+ info->indev = NULL;
+ break;
+ }
+ }
+ if (!info->outdev)
+ info->outdev = info->indev;
+
+ info->hw_outdev = info->indev;
+
+ if (nf_flowtable_hw_offload(flowtable) &&
+ nft_is_valid_ether_device(info->indev))
+ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
+}
+
+static bool nft_flowtable_find_dev(const struct net_device *dev,
+ struct nft_flowtable *ft)
+{
+ struct nft_hook *hook;
+ bool found = false;
+
+ list_for_each_entry_rcu(hook, &ft->hook_list, list) {
+ if (!nft_hook_find_ops_rcu(hook, dev))
+ continue;
+
+ found = true;
+ break;
+ }
+
+ return found;
+}
+
+static void nft_dev_forward_path(struct nf_flow_route *route,
+ const struct nf_conn *ct,
+ enum ip_conntrack_dir dir,
+ struct nft_flowtable *ft)
+{
+ const struct dst_entry *dst = route->tuple[dir].dst;
+ struct net_device_path_stack stack;
+ struct nft_forward_info info = {};
+ unsigned char ha[ETH_ALEN];
+ int i;
+
+ if (nft_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
+ nft_dev_path_info(&stack, &info, ha, &ft->data);
+
+ if (!info.indev || !nft_flowtable_find_dev(info.indev, ft))
+ return;
+
+ route->tuple[!dir].in.ifindex = info.indev->ifindex;
+ for (i = 0; i < info.num_encaps; i++) {
+ route->tuple[!dir].in.encap[i].id = info.encap[i].id;
+ route->tuple[!dir].in.encap[i].proto = info.encap[i].proto;
+ }
+ route->tuple[!dir].in.num_encaps = info.num_encaps;
+ route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
+
+ if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
+ memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
+ memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
+ route->tuple[dir].out.ifindex = info.outdev->ifindex;
+ route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex;
+ route->tuple[dir].xmit_type = info.xmit_type;
+ }
+}
+
+int nft_flow_route(const struct nft_pktinfo *pkt, const struct nf_conn *ct,
+ struct nf_flow_route *route, enum ip_conntrack_dir dir,
+ struct nft_flowtable *ft)
+{
+ struct dst_entry *this_dst = skb_dst(pkt->skb);
+ struct dst_entry *other_dst = NULL;
+ struct flowi fl;
+
+ memset(&fl, 0, sizeof(fl));
+ switch (nft_pf(pkt)) {
+ case NFPROTO_IPV4:
+ fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
+ fl.u.ip4.saddr = ct->tuplehash[!dir].tuple.src.u3.ip;
+ fl.u.ip4.flowi4_oif = nft_in(pkt)->ifindex;
+ fl.u.ip4.flowi4_iif = this_dst->dev->ifindex;
+ fl.u.ip4.flowi4_dscp = ip4h_dscp(ip_hdr(pkt->skb));
+ fl.u.ip4.flowi4_mark = pkt->skb->mark;
+ fl.u.ip4.flowi4_flags = FLOWI_FLAG_ANYSRC;
+ break;
+ case NFPROTO_IPV6:
+ fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
+ fl.u.ip6.saddr = ct->tuplehash[!dir].tuple.src.u3.in6;
+ fl.u.ip6.flowi6_oif = nft_in(pkt)->ifindex;
+ fl.u.ip6.flowi6_iif = this_dst->dev->ifindex;
+ fl.u.ip6.flowlabel = ip6_flowinfo(ipv6_hdr(pkt->skb));
+ fl.u.ip6.flowi6_mark = pkt->skb->mark;
+ fl.u.ip6.flowi6_flags = FLOWI_FLAG_ANYSRC;
+ break;
+ }
+
+ if (!dst_hold_safe(this_dst))
+ return -ENOENT;
+
+ nf_route(nft_net(pkt), &other_dst, &fl, false, nft_pf(pkt));
+ if (!other_dst) {
+ dst_release(this_dst);
+ return -ENOENT;
+ }
+
+ nft_default_forward_path(route, this_dst, dir);
+ nft_default_forward_path(route, other_dst, !dir);
+
+ if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
+ route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
+ nft_dev_forward_path(route, ct, dir, ft);
+ nft_dev_forward_path(route, ct, !dir, ft);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nft_flow_route);
diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
index 14dd1c0698c3..b8f76c9057fd 100644
--- a/net/netfilter/nft_flow_offload.c
+++ b/net/netfilter/nft_flow_offload.c
@@ -20,258 +20,6 @@ struct nft_flow_offload {
struct nft_flowtable *flowtable;
};
-static enum flow_offload_xmit_type nft_xmit_type(struct dst_entry *dst)
-{
- if (dst_xfrm(dst))
- return FLOW_OFFLOAD_XMIT_XFRM;
-
- return FLOW_OFFLOAD_XMIT_NEIGH;
-}
-
-static void nft_default_forward_path(struct nf_flow_route *route,
- struct dst_entry *dst_cache,
- enum ip_conntrack_dir dir)
-{
- route->tuple[!dir].in.ifindex = dst_cache->dev->ifindex;
- route->tuple[dir].dst = dst_cache;
- route->tuple[dir].xmit_type = nft_xmit_type(dst_cache);
-}
-
-static bool nft_is_valid_ether_device(const struct net_device *dev)
-{
- if (!dev || (dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER ||
- dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr))
- return false;
-
- return true;
-}
-
-static int nft_dev_fill_forward_path(const struct nf_flow_route *route,
- const struct dst_entry *dst_cache,
- const struct nf_conn *ct,
- enum ip_conntrack_dir dir, u8 *ha,
- struct net_device_path_stack *stack)
-{
- const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
- struct net_device *dev = dst_cache->dev;
- struct neighbour *n;
- u8 nud_state;
-
- if (!nft_is_valid_ether_device(dev))
- goto out;
-
- n = dst_neigh_lookup(dst_cache, daddr);
- if (!n)
- return -1;
-
- read_lock_bh(&n->lock);
- nud_state = n->nud_state;
- ether_addr_copy(ha, n->ha);
- read_unlock_bh(&n->lock);
- neigh_release(n);
-
- if (!(nud_state & NUD_VALID))
- return -1;
-
-out:
- return dev_fill_forward_path(dev, ha, stack);
-}
-
-struct nft_forward_info {
- const struct net_device *indev;
- const struct net_device *outdev;
- const struct net_device *hw_outdev;
- struct id {
- __u16 id;
- __be16 proto;
- } encap[NF_FLOW_TABLE_ENCAP_MAX];
- u8 num_encaps;
- u8 ingress_vlans;
- u8 h_source[ETH_ALEN];
- u8 h_dest[ETH_ALEN];
- enum flow_offload_xmit_type xmit_type;
-};
-
-static void nft_dev_path_info(const struct net_device_path_stack *stack,
- struct nft_forward_info *info,
- unsigned char *ha, struct nf_flowtable *flowtable)
-{
- const struct net_device_path *path;
- int i;
-
- memcpy(info->h_dest, ha, ETH_ALEN);
-
- for (i = 0; i < stack->num_paths; i++) {
- path = &stack->path[i];
- switch (path->type) {
- case DEV_PATH_ETHERNET:
- case DEV_PATH_DSA:
- case DEV_PATH_VLAN:
- case DEV_PATH_PPPOE:
- info->indev = path->dev;
- if (is_zero_ether_addr(info->h_source))
- memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
-
- if (path->type == DEV_PATH_ETHERNET)
- break;
- if (path->type == DEV_PATH_DSA) {
- i = stack->num_paths;
- break;
- }
-
- /* DEV_PATH_VLAN and DEV_PATH_PPPOE */
- if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) {
- info->indev = NULL;
- break;
- }
- if (!info->outdev)
- info->outdev = path->dev;
- info->encap[info->num_encaps].id = path->encap.id;
- info->encap[info->num_encaps].proto = path->encap.proto;
- info->num_encaps++;
- if (path->type == DEV_PATH_PPPOE)
- memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
- break;
- case DEV_PATH_BRIDGE:
- if (is_zero_ether_addr(info->h_source))
- memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
-
- switch (path->bridge.vlan_mode) {
- case DEV_PATH_BR_VLAN_UNTAG_HW:
- info->ingress_vlans |= BIT(info->num_encaps - 1);
- break;
- case DEV_PATH_BR_VLAN_TAG:
- info->encap[info->num_encaps].id = path->bridge.vlan_id;
- info->encap[info->num_encaps].proto = path->bridge.vlan_proto;
- info->num_encaps++;
- break;
- case DEV_PATH_BR_VLAN_UNTAG:
- info->num_encaps--;
- break;
- case DEV_PATH_BR_VLAN_KEEP:
- break;
- }
- info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
- break;
- default:
- info->indev = NULL;
- break;
- }
- }
- if (!info->outdev)
- info->outdev = info->indev;
-
- info->hw_outdev = info->indev;
-
- if (nf_flowtable_hw_offload(flowtable) &&
- nft_is_valid_ether_device(info->indev))
- info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
-}
-
-static bool nft_flowtable_find_dev(const struct net_device *dev,
- struct nft_flowtable *ft)
-{
- struct nft_hook *hook;
- bool found = false;
-
- list_for_each_entry_rcu(hook, &ft->hook_list, list) {
- if (!nft_hook_find_ops_rcu(hook, dev))
- continue;
-
- found = true;
- break;
- }
-
- return found;
-}
-
-static void nft_dev_forward_path(struct nf_flow_route *route,
- const struct nf_conn *ct,
- enum ip_conntrack_dir dir,
- struct nft_flowtable *ft)
-{
- const struct dst_entry *dst = route->tuple[dir].dst;
- struct net_device_path_stack stack;
- struct nft_forward_info info = {};
- unsigned char ha[ETH_ALEN];
- int i;
-
- if (nft_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
- nft_dev_path_info(&stack, &info, ha, &ft->data);
-
- if (!info.indev || !nft_flowtable_find_dev(info.indev, ft))
- return;
-
- route->tuple[!dir].in.ifindex = info.indev->ifindex;
- for (i = 0; i < info.num_encaps; i++) {
- route->tuple[!dir].in.encap[i].id = info.encap[i].id;
- route->tuple[!dir].in.encap[i].proto = info.encap[i].proto;
- }
- route->tuple[!dir].in.num_encaps = info.num_encaps;
- route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
-
- if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
- memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
- memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
- route->tuple[dir].out.ifindex = info.outdev->ifindex;
- route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex;
- route->tuple[dir].xmit_type = info.xmit_type;
- }
-}
-
-static int nft_flow_route(const struct nft_pktinfo *pkt,
- const struct nf_conn *ct,
- struct nf_flow_route *route,
- enum ip_conntrack_dir dir,
- struct nft_flowtable *ft)
-{
- struct dst_entry *this_dst = skb_dst(pkt->skb);
- struct dst_entry *other_dst = NULL;
- struct flowi fl;
-
- memset(&fl, 0, sizeof(fl));
- switch (nft_pf(pkt)) {
- case NFPROTO_IPV4:
- fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
- fl.u.ip4.saddr = ct->tuplehash[!dir].tuple.src.u3.ip;
- fl.u.ip4.flowi4_oif = nft_in(pkt)->ifindex;
- fl.u.ip4.flowi4_iif = this_dst->dev->ifindex;
- fl.u.ip4.flowi4_dscp = ip4h_dscp(ip_hdr(pkt->skb));
- fl.u.ip4.flowi4_mark = pkt->skb->mark;
- fl.u.ip4.flowi4_flags = FLOWI_FLAG_ANYSRC;
- break;
- case NFPROTO_IPV6:
- fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
- fl.u.ip6.saddr = ct->tuplehash[!dir].tuple.src.u3.in6;
- fl.u.ip6.flowi6_oif = nft_in(pkt)->ifindex;
- fl.u.ip6.flowi6_iif = this_dst->dev->ifindex;
- fl.u.ip6.flowlabel = ip6_flowinfo(ipv6_hdr(pkt->skb));
- fl.u.ip6.flowi6_mark = pkt->skb->mark;
- fl.u.ip6.flowi6_flags = FLOWI_FLAG_ANYSRC;
- break;
- }
-
- if (!dst_hold_safe(this_dst))
- return -ENOENT;
-
- nf_route(nft_net(pkt), &other_dst, &fl, false, nft_pf(pkt));
- if (!other_dst) {
- dst_release(this_dst);
- return -ENOENT;
- }
-
- nft_default_forward_path(route, this_dst, dir);
- nft_default_forward_path(route, other_dst, !dir);
-
- if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
- route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
- nft_dev_forward_path(route, ct, dir, ft);
- nft_dev_forward_path(route, ct, !dir, ft);
- }
-
- return 0;
-}
-
static bool nft_flow_offload_skip(struct sk_buff *skb, int family)
{
if (skb_sec_path(skb))
--
2.30.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH nf-next 2/5] netfilter: flowtable: consolidate xmit path
2025-10-10 11:18 [PATCH nf-next 0/5] flowtable: consolidate xmit path Pablo Neira Ayuso
2025-10-10 11:18 ` [PATCH nf-next 1/5] netfilter: flowtable: move path discovery infrastructure to its own file Pablo Neira Ayuso
@ 2025-10-10 11:18 ` Pablo Neira Ayuso
2025-10-12 12:26 ` Florian Westphal
2025-10-10 11:18 ` [PATCH nf-next 3/5] netfilter: flowtable: inline vlan encapsulation in " Pablo Neira Ayuso
` (2 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2025-10-10 11:18 UTC (permalink / raw)
To: netfilter-devel
Use dev_queue_xmit() for the XMIT_NEIGH case. Store the interface index
of the real device behind the vlan/pppoe device, this introduces an
extra lookup for the real device in the xmit path because rt->dst.dev
provides the vlan/pppoe device.
XMIT_NEIGH now looks more similar to XMIT_DIRECT but the check for stale
dst and the neighbour lookup still remain in place which is convenient
to deal with network topology changes.
Note that nft_flow_route() needs to relax the check for _XMIT_NEIGH so
the existing basic xfrm offload (which only works in one direction) does
not break.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_flow_table.h | 1 +
net/netfilter/nf_flow_table_core.c | 1 +
net/netfilter/nf_flow_table_ip.c | 87 ++++++++++++++++-----------
net/netfilter/nf_flow_table_path.c | 7 +--
4 files changed, 57 insertions(+), 39 deletions(-)
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index e9f72d2558e9..efede742106c 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -140,6 +140,7 @@ struct flow_offload_tuple {
u16 mtu;
union {
struct {
+ u32 ifidx;
struct dst_entry *dst_cache;
u32 dst_cookie;
};
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index 9441ac3d8c1a..98d7b3708602 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -132,6 +132,7 @@ static int flow_offload_fill_route(struct flow_offload *flow,
break;
case FLOW_OFFLOAD_XMIT_XFRM:
case FLOW_OFFLOAD_XMIT_NEIGH:
+ flow_tuple->ifidx = route->tuple[dir].out.ifindex;
flow_tuple->dst_cache = dst;
flow_tuple->dst_cookie = flow_offload_dst_cookie(flow_tuple);
break;
diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 8cd4cf7ae211..8b74fb34998e 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -333,19 +333,18 @@ static void nf_flow_encap_pop(struct sk_buff *skb,
}
}
+struct nf_flow_xmit {
+ const void *dest;
+ const void *source;
+ struct net_device *outdev;
+};
+
static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
- const struct flow_offload_tuple_rhash *tuplehash,
- unsigned short type)
+ struct nf_flow_xmit *xmit)
{
- struct net_device *outdev;
-
- outdev = dev_get_by_index_rcu(net, tuplehash->tuple.out.ifidx);
- if (!outdev)
- return NF_DROP;
-
- skb->dev = outdev;
- dev_hard_header(skb, skb->dev, type, tuplehash->tuple.out.h_dest,
- tuplehash->tuple.out.h_source, skb->len);
+ skb->dev = xmit->outdev;
+ dev_hard_header(skb, skb->dev, ntohs(skb->protocol),
+ xmit->dest, xmit->source, skb->len);
dev_queue_xmit(skb);
return NF_STOLEN;
@@ -424,10 +423,10 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
struct nf_flowtable_ctx ctx = {
.in = state->in,
};
+ struct nf_flow_xmit xmit = {};
struct flow_offload *flow;
- struct net_device *outdev;
+ struct neighbour *neigh;
struct rtable *rt;
- __be32 nexthop;
int ret;
tuplehash = nf_flow_offload_lookup(&ctx, flow_table, skb);
@@ -454,25 +453,34 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
switch (tuplehash->tuple.xmit_type) {
case FLOW_OFFLOAD_XMIT_NEIGH:
rt = dst_rtable(tuplehash->tuple.dst_cache);
- outdev = rt->dst.dev;
- skb->dev = outdev;
- nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
+ xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.ifidx);
+ if (!xmit.outdev) {
+ flow_offload_teardown(flow);
+ return NF_DROP;
+ }
+ neigh = ip_neigh_gw4(rt->dst.dev, rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr));
+ if (IS_ERR(neigh)) {
+ flow_offload_teardown(flow);
+ return NF_DROP;
+ }
+ xmit.dest = neigh->ha;
skb_dst_set_noref(skb, &rt->dst);
- neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb);
- ret = NF_STOLEN;
break;
case FLOW_OFFLOAD_XMIT_DIRECT:
- ret = nf_flow_queue_xmit(state->net, skb, tuplehash, ETH_P_IP);
- if (ret == NF_DROP)
+ xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.out.ifidx);
+ if (!xmit.outdev) {
flow_offload_teardown(flow);
+ return NF_DROP;
+ }
+ xmit.dest = tuplehash->tuple.out.h_dest;
+ xmit.source = tuplehash->tuple.out.h_source;
break;
default:
WARN_ON_ONCE(1);
- ret = NF_DROP;
- break;
+ return NF_DROP;
}
- return ret;
+ return nf_flow_queue_xmit(state->net, skb, &xmit);
}
EXPORT_SYMBOL_GPL(nf_flow_offload_ip_hook);
@@ -719,9 +727,9 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
struct nf_flowtable_ctx ctx = {
.in = state->in,
};
- const struct in6_addr *nexthop;
+ struct nf_flow_xmit xmit = {};
struct flow_offload *flow;
- struct net_device *outdev;
+ struct neighbour *neigh;
struct rt6_info *rt;
int ret;
@@ -749,24 +757,33 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
switch (tuplehash->tuple.xmit_type) {
case FLOW_OFFLOAD_XMIT_NEIGH:
rt = dst_rt6_info(tuplehash->tuple.dst_cache);
- outdev = rt->dst.dev;
- skb->dev = outdev;
- nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
+ xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.out.ifidx);
+ if (!xmit.outdev) {
+ flow_offload_teardown(flow);
+ return NF_DROP;
+ }
+ neigh = ip_neigh_gw6(rt->dst.dev, rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6));
+ if (IS_ERR(neigh)) {
+ flow_offload_teardown(flow);
+ return NF_DROP;
+ }
+ xmit.dest = neigh->ha;
skb_dst_set_noref(skb, &rt->dst);
- neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb);
- ret = NF_STOLEN;
break;
case FLOW_OFFLOAD_XMIT_DIRECT:
- ret = nf_flow_queue_xmit(state->net, skb, tuplehash, ETH_P_IPV6);
- if (ret == NF_DROP)
+ xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.out.ifidx);
+ if (!xmit.outdev) {
flow_offload_teardown(flow);
+ return NF_DROP;
+ }
+ xmit.dest = tuplehash->tuple.out.h_dest;
+ xmit.source = tuplehash->tuple.out.h_source;
break;
default:
WARN_ON_ONCE(1);
- ret = NF_DROP;
- break;
+ return NF_DROP;
}
- return ret;
+ return nf_flow_queue_xmit(state->net, skb, &xmit);
}
EXPORT_SYMBOL_GPL(nf_flow_offload_ipv6_hook);
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 159aa5c8da60..15c042cab9fb 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -204,11 +204,11 @@ static void nft_dev_forward_path(struct nf_flow_route *route,
}
route->tuple[!dir].in.num_encaps = info.num_encaps;
route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
+ route->tuple[dir].out.ifindex = info.outdev->ifindex;
if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
- route->tuple[dir].out.ifindex = info.outdev->ifindex;
route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex;
route->tuple[dir].xmit_type = info.xmit_type;
}
@@ -256,11 +256,10 @@ int nft_flow_route(const struct nft_pktinfo *pkt, const struct nf_conn *ct,
nft_default_forward_path(route, this_dst, dir);
nft_default_forward_path(route, other_dst, !dir);
- if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
- route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
+ if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH)
nft_dev_forward_path(route, ct, dir, ft);
+ if (route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH)
nft_dev_forward_path(route, ct, !dir, ft);
- }
return 0;
}
--
2.30.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH nf-next 2/5] netfilter: flowtable: consolidate xmit path
2025-10-10 11:18 ` [PATCH nf-next 2/5] netfilter: flowtable: consolidate xmit path Pablo Neira Ayuso
@ 2025-10-12 12:26 ` Florian Westphal
2025-10-27 23:48 ` Pablo Neira Ayuso
0 siblings, 1 reply; 9+ messages in thread
From: Florian Westphal @ 2025-10-12 12:26 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> Use dev_queue_xmit() for the XMIT_NEIGH case. Store the interface index
> of the real device behind the vlan/pppoe device, this introduces an
> extra lookup for the real device in the xmit path because rt->dst.dev
> provides the vlan/pppoe device.
Will this scale? netdev_by_index only has a fixed table of 256 slots,
so with 8k vlans or so this will have a 30-ish netdev list walk.
[ EDIT: I see now that nf_flow_queue_xmit() already does that.
So I guess its either not an issue or not yet and it can be
optimized later. So disregard this ]
> case FLOW_OFFLOAD_XMIT_NEIGH:
> rt = dst_rtable(tuplehash->tuple.dst_cache);
> - outdev = rt->dst.dev;
> - skb->dev = outdev;
> - nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
> + xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.ifidx);
Why do this if we already have dst_cache?
The above explanation (rt->dst.dev could be a tunnel device, whereas
the latter fetches phyical / lowest device) from the commit message
makes that clear; but I think a short comment would help.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH nf-next 2/5] netfilter: flowtable: consolidate xmit path
2025-10-12 12:26 ` Florian Westphal
@ 2025-10-27 23:48 ` Pablo Neira Ayuso
0 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2025-10-27 23:48 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On Sun, Oct 12, 2025 at 02:26:20PM +0200, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > Use dev_queue_xmit() for the XMIT_NEIGH case. Store the interface index
> > of the real device behind the vlan/pppoe device, this introduces an
> > extra lookup for the real device in the xmit path because rt->dst.dev
> > provides the vlan/pppoe device.
>
> Will this scale? netdev_by_index only has a fixed table of 256 slots,
> so with 8k vlans or so this will have a 30-ish netdev list walk.
>
> [ EDIT: I see now that nf_flow_queue_xmit() already does that.
> So I guess its either not an issue or not yet and it can be
> optimized later. So disregard this ]
Yes, that will need a look closer or later.
> > case FLOW_OFFLOAD_XMIT_NEIGH:
> > rt = dst_rtable(tuplehash->tuple.dst_cache);
> > - outdev = rt->dst.dev;
> > - skb->dev = outdev;
> > - nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
> > + xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.ifidx);
>
> Why do this if we already have dst_cache?
This is to skip one level of indirection, ie. dst_cache points to the
vlan device, not the real device. The idea is that the flowtable gains
control on the xmit path so the flowtable pushes l2/l3 headers and
send the packets directly to the "real" netdevice.
> The above explanation (rt->dst.dev could be a tunnel device, whereas
> the latter fetches phyical / lowest device) from the commit message
> makes that clear; but I think a short comment would help.
Yes, I can add a comment on this.
Thanks.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH nf-next 3/5] netfilter: flowtable: inline vlan encapsulation in xmit path
2025-10-10 11:18 [PATCH nf-next 0/5] flowtable: consolidate xmit path Pablo Neira Ayuso
2025-10-10 11:18 ` [PATCH nf-next 1/5] netfilter: flowtable: move path discovery infrastructure to its own file Pablo Neira Ayuso
2025-10-10 11:18 ` [PATCH nf-next 2/5] netfilter: flowtable: consolidate xmit path Pablo Neira Ayuso
@ 2025-10-10 11:18 ` Pablo Neira Ayuso
2025-10-10 11:18 ` [PATCH nf-next 4/5] netfilter: flowtable: inline pppoe " Pablo Neira Ayuso
2025-10-10 11:18 ` [PATCH nf-next 5/5] netfilter: flowtable: remove hw_ifidx Pablo Neira Ayuso
4 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2025-10-10 11:18 UTC (permalink / raw)
To: netfilter-devel
Push the vlan header from the flowtable xmit path, instead of passing
the packet to the vlan device.
This is based on a patch originally written by wenxu.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_flow_table_ip.c | 20 ++++++++++++++++++++
net/netfilter/nf_flow_table_path.c | 7 ++++---
2 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 8b74fb34998e..2d11c46a925c 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -413,6 +413,23 @@ static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx,
return 1;
}
+static int nf_flow_encap_push(struct sk_buff *skb, struct flow_offload_tuple *tuple)
+{
+ int i;
+
+ for (i = 0; i < tuple->encap_num; i++) {
+ switch (tuple->encap[i].proto) {
+ case htons(ETH_P_8021Q):
+ case htons(ETH_P_8021AD):
+ if (skb_vlan_push(skb, tuple->encap[i].proto, tuple->encap[i].id) < 0)
+ return -1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
unsigned int
nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
@@ -450,6 +467,9 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
dir = tuplehash->tuple.dir;
flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
+ if (nf_flow_encap_push(skb, &flow->tuplehash[!dir].tuple) < 0)
+ return NF_DROP;
+
switch (tuplehash->tuple.xmit_type) {
case FLOW_OFFLOAD_XMIT_NEIGH:
rt = dst_rtable(tuplehash->tuple.dst_cache);
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 15c042cab9fb..1cb04c3e6dde 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -119,13 +119,14 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
info->indev = NULL;
break;
}
- if (!info->outdev)
- info->outdev = path->dev;
info->encap[info->num_encaps].id = path->encap.id;
info->encap[info->num_encaps].proto = path->encap.proto;
info->num_encaps++;
- if (path->type == DEV_PATH_PPPOE)
+ if (path->type == DEV_PATH_PPPOE) {
+ if (!info->outdev)
+ info->outdev = path->dev;
memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
+ }
break;
case DEV_PATH_BRIDGE:
if (is_zero_ether_addr(info->h_source))
--
2.30.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH nf-next 4/5] netfilter: flowtable: inline pppoe encapsulation in xmit path
2025-10-10 11:18 [PATCH nf-next 0/5] flowtable: consolidate xmit path Pablo Neira Ayuso
` (2 preceding siblings ...)
2025-10-10 11:18 ` [PATCH nf-next 3/5] netfilter: flowtable: inline vlan encapsulation in " Pablo Neira Ayuso
@ 2025-10-10 11:18 ` Pablo Neira Ayuso
2025-10-10 11:18 ` [PATCH nf-next 5/5] netfilter: flowtable: remove hw_ifidx Pablo Neira Ayuso
4 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2025-10-10 11:18 UTC (permalink / raw)
To: netfilter-devel
Push the pppoe header from the flowtable xmit path, instead of passing
the packet to the pppoe device which delivers the packet to the
userspace pppd daemon for encapsulation.
This is based on a patch originally written by wenxu.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_flow_table_ip.c | 42 ++++++++++++++++++++++++++++++
net/netfilter/nf_flow_table_path.c | 9 ++-----
2 files changed, 44 insertions(+), 7 deletions(-)
diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 2d11c46a925c..be21600cff53 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -413,6 +413,44 @@ static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx,
return 1;
}
+static int nf_flow_pppoe_push(struct sk_buff *skb, u16 id)
+{
+ int data_len = skb->len + sizeof(__be16);
+ struct ppp_hdr {
+ struct pppoe_hdr hdr;
+ __be16 proto;
+ } *ph;
+ __be16 proto;
+
+ if (skb_cow_head(skb, PPPOE_SES_HLEN))
+ return -1;
+
+ switch (skb->protocol) {
+ case htons(ETH_P_IP):
+ proto = htons(PPP_IP);
+ break;
+ case htons(ETH_P_IPV6):
+ proto = htons(PPP_IPV6);
+ break;
+ default:
+ return -1;
+ }
+
+ __skb_push(skb, PPPOE_SES_HLEN);
+ skb_reset_network_header(skb);
+
+ ph = (struct ppp_hdr *)(skb->data);
+ ph->hdr.ver = 1;
+ ph->hdr.type = 1;
+ ph->hdr.code = 0;
+ ph->hdr.sid = htons(id);
+ ph->hdr.length = htons(data_len);
+ ph->proto = proto;
+ skb->protocol = htons(ETH_P_PPP_SES);
+
+ return 0;
+}
+
static int nf_flow_encap_push(struct sk_buff *skb, struct flow_offload_tuple *tuple)
{
int i;
@@ -424,6 +462,10 @@ static int nf_flow_encap_push(struct sk_buff *skb, struct flow_offload_tuple *tu
if (skb_vlan_push(skb, tuple->encap[i].proto, tuple->encap[i].id) < 0)
return -1;
break;
+ case htons(ETH_P_PPP_SES):
+ if (nf_flow_pppoe_push(skb, tuple->encap[i].id) < 0)
+ return -1;
+ break;
}
}
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 1cb04c3e6dde..7ba6a0c4e5d8 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -122,11 +122,8 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
info->encap[info->num_encaps].id = path->encap.id;
info->encap[info->num_encaps].proto = path->encap.proto;
info->num_encaps++;
- if (path->type == DEV_PATH_PPPOE) {
- if (!info->outdev)
- info->outdev = path->dev;
+ if (path->type == DEV_PATH_PPPOE)
memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
- }
break;
case DEV_PATH_BRIDGE:
if (is_zero_ether_addr(info->h_source))
@@ -154,9 +151,7 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
break;
}
}
- if (!info->outdev)
- info->outdev = info->indev;
-
+ info->outdev = info->indev;
info->hw_outdev = info->indev;
if (nf_flowtable_hw_offload(flowtable) &&
--
2.30.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH nf-next 5/5] netfilter: flowtable: remove hw_ifidx
2025-10-10 11:18 [PATCH nf-next 0/5] flowtable: consolidate xmit path Pablo Neira Ayuso
` (3 preceding siblings ...)
2025-10-10 11:18 ` [PATCH nf-next 4/5] netfilter: flowtable: inline pppoe " Pablo Neira Ayuso
@ 2025-10-10 11:18 ` Pablo Neira Ayuso
4 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2025-10-10 11:18 UTC (permalink / raw)
To: netfilter-devel
hw_ifidx was originally introduced to store the real netdevice as a
requirement for the hardware offload support in:
73f97025a972 ("netfilter: nft_flow_offload: use direct xmit if hardware offload is enabled")
Since ("netfilter: flowtable: consolidate xmit path"), ifidx and
hw_ifidx points to the real device in the xmit path, remove it.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_flow_table.h | 1 -
net/netfilter/nf_flow_table_core.c | 1 -
net/netfilter/nf_flow_table_offload.c | 2 +-
net/netfilter/nf_flow_table_path.c | 3 ---
4 files changed, 1 insertion(+), 6 deletions(-)
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index efede742106c..89cfe7228398 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -146,7 +146,6 @@ struct flow_offload_tuple {
};
struct {
u32 ifidx;
- u32 hw_ifidx;
u8 h_source[ETH_ALEN];
u8 h_dest[ETH_ALEN];
} out;
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index 98d7b3708602..6c6a5165f993 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -127,7 +127,6 @@ static int flow_offload_fill_route(struct flow_offload *flow,
memcpy(flow_tuple->out.h_source, route->tuple[dir].out.h_source,
ETH_ALEN);
flow_tuple->out.ifidx = route->tuple[dir].out.ifindex;
- flow_tuple->out.hw_ifidx = route->tuple[dir].out.hw_ifindex;
dst_release(dst);
break;
case FLOW_OFFLOAD_XMIT_XFRM:
diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
index e06bc36f49fe..d8f7bfd60ac6 100644
--- a/net/netfilter/nf_flow_table_offload.c
+++ b/net/netfilter/nf_flow_table_offload.c
@@ -555,7 +555,7 @@ static void flow_offload_redirect(struct net *net,
switch (this_tuple->xmit_type) {
case FLOW_OFFLOAD_XMIT_DIRECT:
this_tuple = &flow->tuplehash[dir].tuple;
- ifindex = this_tuple->out.hw_ifidx;
+ ifindex = this_tuple->out.ifidx;
break;
case FLOW_OFFLOAD_XMIT_NEIGH:
other_tuple = &flow->tuplehash[!dir].tuple;
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 7ba6a0c4e5d8..50b2b7d0c579 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -75,7 +75,6 @@ static int nft_dev_fill_forward_path(const struct nf_flow_route *route,
struct nft_forward_info {
const struct net_device *indev;
const struct net_device *outdev;
- const struct net_device *hw_outdev;
struct id {
__u16 id;
__be16 proto;
@@ -152,7 +151,6 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
}
}
info->outdev = info->indev;
- info->hw_outdev = info->indev;
if (nf_flowtable_hw_offload(flowtable) &&
nft_is_valid_ether_device(info->indev))
@@ -205,7 +203,6 @@ static void nft_dev_forward_path(struct nf_flow_route *route,
if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
- route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex;
route->tuple[dir].xmit_type = info.xmit_type;
}
}
--
2.30.2
^ permalink raw reply related [flat|nested] 9+ messages in thread