]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netfilter: fib: avoid lookup if socket is available
authorFlorian Westphal <fw@strlen.de>
Thu, 20 Feb 2025 13:07:01 +0000 (14:07 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 21 Mar 2025 09:12:15 +0000 (10:12 +0100)
In case the fib match is used from the input hook we can avoid the fib
lookup if early demux assigned a socket for us: check that the input
interface matches sk-cached one.

Rework the existing 'lo bypass' logic to first check sk, then
for loopback interface type to elide the fib lookup.

This speeds up fib matching a little, before:
93.08 GBit/s (no rules at all)
75.1  GBit/s ("fib saddr . iif oif missing drop" in prerouting)
75.62 GBit/s ("fib saddr . iif oif missing drop" in input)

After:
92.48 GBit/s (no rules at all)
75.62 GBit/s (fib rule in prerouting)
90.37 GBit/s (fib rule in input).

Numbers for the 'no rules' and 'prerouting' are expected to
closely match in-between runs, the 3rd/input test case exercises the
the 'avoid lookup if cached ifindex in sk matches' case.

Test used iperf3 via veth interface, lo can't be used due to existing
loopback test.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nft_fib.h
net/ipv4/netfilter/nft_fib_ipv4.c
net/ipv6/netfilter/nft_fib_ipv6.c

index 38cae7113de4621824472352f3f0ab9e1054707e..6e202ed5e63f3ca52eebff4716ef3c9066167555 100644 (file)
@@ -18,6 +18,27 @@ nft_fib_is_loopback(const struct sk_buff *skb, const struct net_device *in)
        return skb->pkt_type == PACKET_LOOPBACK || in->flags & IFF_LOOPBACK;
 }
 
+static inline bool nft_fib_can_skip(const struct nft_pktinfo *pkt)
+{
+       const struct net_device *indev = nft_in(pkt);
+       const struct sock *sk;
+
+       switch (nft_hook(pkt)) {
+       case NF_INET_PRE_ROUTING:
+       case NF_INET_INGRESS:
+       case NF_INET_LOCAL_IN:
+               break;
+       default:
+               return false;
+       }
+
+       sk = pkt->skb->sk;
+       if (sk && sk_fullsock(sk))
+              return sk->sk_rx_dst_ifindex == indev->ifindex;
+
+       return nft_fib_is_loopback(pkt->skb, indev);
+}
+
 int nft_fib_dump(struct sk_buff *skb, const struct nft_expr *expr, bool reset);
 int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                 const struct nlattr * const tb[]);
index 625adbc420370835b55fe723070d244f68e1574f..9082ca17e845cbb7b3e3e09309fb5b876c1707a7 100644 (file)
@@ -71,6 +71,11 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs,
        const struct net_device *oif;
        const struct net_device *found;
 
+       if (nft_fib_can_skip(pkt)) {
+               nft_fib_store_result(dest, priv, nft_in(pkt));
+               return;
+       }
+
        /*
         * Do not set flowi4_oif, it restricts results (for example, asking
         * for oif 3 will get RTN_UNICAST result even if the daddr exits
@@ -85,12 +90,6 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs,
        else
                oif = NULL;
 
-       if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
-           nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
-               nft_fib_store_result(dest, priv, nft_in(pkt));
-               return;
-       }
-
        iph = skb_header_pointer(pkt->skb, noff, sizeof(_iph), &_iph);
        if (!iph) {
                regs->verdict.code = NFT_BREAK;
index c9f1634b3838aeff4cd5002545f4ac496ce0bdc6..7fd9d7b21cd42d1c756075cb5d1e9aab89ee3350 100644 (file)
@@ -170,6 +170,11 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
        struct rt6_info *rt;
        int lookup_flags;
 
+       if (nft_fib_can_skip(pkt)) {
+               nft_fib_store_result(dest, priv, nft_in(pkt));
+               return;
+       }
+
        if (priv->flags & NFTA_FIB_F_IIF)
                oif = nft_in(pkt);
        else if (priv->flags & NFTA_FIB_F_OIF)
@@ -181,17 +186,13 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
                return;
        }
 
-       lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif, iph);
-
-       if (nft_hook(pkt) == NF_INET_PRE_ROUTING ||
-           nft_hook(pkt) == NF_INET_INGRESS) {
-               if (nft_fib_is_loopback(pkt->skb, nft_in(pkt)) ||
-                   nft_fib_v6_skip_icmpv6(pkt->skb, pkt->tprot, iph)) {
-                       nft_fib_store_result(dest, priv, nft_in(pkt));
-                       return;
-               }
+       if (nft_fib_v6_skip_icmpv6(pkt->skb, pkt->tprot, iph)) {
+               nft_fib_store_result(dest, priv, nft_in(pkt));
+               return;
        }
 
+       lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif, iph);
+
        *dest = 0;
        rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, pkt->skb,
                                      lookup_flags);