On Fri, Jun 27, 2025 at 02:45:28PM +0200, Lorenzo Bianconi wrote:
Introduce SW acceleration for IPIP tunnels in the netfilter flowtable infrastructure. IPIP SW acceleration can be tested running the following scenario where the traffic is forwarded between two NICs (eth0 and eth1) and an IPIP tunnel is used to access a remote site (using eth1 as the underlay device):
ETH0 -- TUN0 <==> ETH1 -- [IP network] -- TUN1 (192.168.100.2)
$ip addr show 6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 00:00:22:33:11:55 brd ff:ff:ff:ff:ff:ff inet 192.168.0.2/24 scope global eth0 valid_lft forever preferred_lft forever 7: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 00:11:22:33:11:55 brd ff:ff:ff:ff:ff:ff inet 192.168.1.1/24 scope global eth1 valid_lft forever preferred_lft forever 8: tun0@NONE: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000 link/ipip 192.168.1.1 peer 192.168.1.2 inet 192.168.100.1/24 scope global tun0 valid_lft forever preferred_lft forever
$ip route show default via 192.168.100.2 dev tun0 192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.2 192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.1 192.168.100.0/24 dev tun0 proto kernel scope link src 192.168.100.1
$nft list ruleset table inet filter { flowtable ft { hook ingress priority filter devices = { eth0, eth1 } }
chain forward { type filter hook forward priority filter; policy accept; meta l4proto { tcp, udp } flow add @ft }
}
Is there a proof that this accelerates forwarding?
I reproduced the scenario described above using veths (something similar to what is done in nft_flowtable.sh) and I got the following results:
- flowtable configured as above between the two router interfaces - TCP stream between client and server going via the IPIP tunnel - TCP stream transmitted into the IPIP tunnel: - net-next: ~41Gbps - net-next + IPIP flowtbale support: ~40Gbps - TCP stream received from the IPIP tunnel: - net-next: ~35Gbps - net-next + IPIP flowtbale support: ~49Gbps
Signed-off-by: Lorenzo Bianconi lorenzo@kernel.org
net/ipv4/ipip.c | 21 +++++++++++++++++++++ net/netfilter/nf_flow_table_ip.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-)
[...]
static bool nf_flow_skb_encap_protocol(struct sk_buff *skb, __be16 proto, u32 *offset) { struct vlan_ethhdr *veth; __be16 inner_proto;
- u16 size;
switch (skb->protocol) {
- case htons(ETH_P_IP):
if (nf_flow_ip4_encap_proto(skb, &size))
*offset += size;
This is blindly skipping the outer IP header.
Do you mean we are supposed to validate the outer IP header performing the sanity checks done in nf_flow_tuple_ip()?
Regards, Lorenzo
case htons(ETH_P_8021Q): if (!pskb_may_pull(skb, skb_mac_offset(skb) + sizeof(*veth))) return false;return true;
@@ -310,6 +328,7 @@ static void nf_flow_encap_pop(struct sk_buff *skb, struct flow_offload_tuple_rhash *tuplehash) { struct vlan_hdr *vlan_hdr;
- u16 size; int i;
for (i = 0; i < tuplehash->tuple.encap_num; i++) { @@ -331,6 +350,12 @@ static void nf_flow_encap_pop(struct sk_buff *skb, break; } }
- if (skb->protocol == htons(ETH_P_IP) &&
nf_flow_ip4_encap_proto(skb, &size)) {
skb_pull(skb, size);
skb_reset_network_header(skb);
- }
I have a similar patch from 2023, I think I keep somewhere in my trees.
} static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb, @@ -357,8 +382,7 @@ nf_flow_offload_lookup(struct nf_flowtable_ctx *ctx, { struct flow_offload_tuple tuple = {};
- if (skb->protocol != htons(ETH_P_IP) &&
!nf_flow_skb_encap_protocol(skb, htons(ETH_P_IP), &ctx->offset))
- if (!nf_flow_skb_encap_protocol(skb, htons(ETH_P_IP), &ctx->offset)) return NULL;
if (nf_flow_tuple_ip(ctx, skb, &tuple) < 0)
-- 2.50.0