Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

netfilter: nft_fib_ipv6: switch to fib6_lookup

Existing code works but it requires a temporary dst object that is
released again right away.

Switch to fib6_lookup + RT6_LOOKUP_F_DST_NOREF: no need for temporary dst
objects and refcount overhead anymore.

Provides ~13% improvement in match performance.

Signed-off-by: Florian Westphal <fw@strlen.de>

+49 -30
+49 -30
net/ipv6/netfilter/nft_fib_ipv6.c
··· 52 52 fl6->flowlabel = (*(__be32 *)iph) & IPV6_FLOWINFO_MASK; 53 53 fl6->flowi6_l3mdev = nft_fib_l3mdev_master_ifindex_rcu(pkt, dev); 54 54 55 - return lookup_flags; 55 + return lookup_flags | RT6_LOOKUP_F_DST_NOREF; 56 + } 57 + 58 + static int nft_fib6_lookup(struct net *net, struct flowi6 *fl6, 59 + struct fib6_result *res, int flags) 60 + { 61 + return fib6_lookup(net, fl6->flowi6_oif, fl6, res, flags); 56 62 } 57 63 58 64 static u32 __nft_fib6_eval_type(const struct nft_fib *priv, ··· 66 60 struct ipv6hdr *iph) 67 61 { 68 62 const struct net_device *dev = NULL; 63 + struct fib6_result res = {}; 69 64 int route_err, addrtype; 70 - struct rt6_info *rt; 71 65 struct flowi6 fl6 = { 72 66 .flowi6_iif = LOOPBACK_IFINDEX, 73 67 .flowi6_proto = pkt->tprot, 74 68 .flowi6_uid = sock_net_uid(nft_net(pkt), NULL), 75 69 }; 70 + int lookup_flags; 76 71 u32 ret = 0; 77 72 78 73 if (priv->flags & NFTA_FIB_F_IIF) ··· 81 74 else if (priv->flags & NFTA_FIB_F_OIF) 82 75 dev = nft_out(pkt); 83 76 84 - nft_fib6_flowi_init(&fl6, priv, pkt, dev, iph); 77 + lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, dev, iph); 85 78 86 79 if (dev && nf_ipv6_chk_addr(nft_net(pkt), &fl6.daddr, dev, true)) 87 80 ret = RTN_LOCAL; 88 81 89 - route_err = nf_ip6_route(nft_net(pkt), (struct dst_entry **)&rt, 90 - flowi6_to_flowi(&fl6), false); 82 + route_err = nft_fib6_lookup(nft_net(pkt), &fl6, &res, lookup_flags); 91 83 if (route_err) 92 84 goto err; 93 85 94 - if (rt->rt6i_flags & RTF_REJECT) { 95 - route_err = rt->dst.error; 96 - dst_release(&rt->dst); 97 - goto err; 98 - } 86 + if (res.fib6_flags & RTF_REJECT) 87 + return res.fib6_type; 99 88 100 - if (ipv6_anycast_destination((struct dst_entry *)rt, &fl6.daddr)) 89 + if (__ipv6_anycast_destination(&res.f6i->fib6_dst, res.fib6_flags, &fl6.daddr)) 101 90 ret = RTN_ANYCAST; 102 - else if (!dev && rt->rt6i_flags & RTF_LOCAL) 91 + else if (!dev && res.fib6_flags & RTF_LOCAL) 103 92 ret = RTN_LOCAL; 104 - 105 - dst_release(&rt->dst); 106 93 107 94 if (ret) 108 95 return ret; ··· 153 152 return ipv6_addr_type(&iph->daddr) & IPV6_ADDR_LINKLOCAL; 154 153 } 155 154 155 + static bool nft_fib6_info_nh_dev_match(const struct net_device *nh_dev, 156 + const struct net_device *dev) 157 + { 158 + return nh_dev == dev || 159 + l3mdev_master_ifindex_rcu(nh_dev) == dev->ifindex; 160 + } 161 + 162 + static bool nft_fib6_info_nh_uses_dev(struct fib6_info *rt, 163 + const struct net_device *dev) 164 + { 165 + const struct net_device *nh_dev; 166 + struct fib6_info *iter; 167 + 168 + nh_dev = fib6_info_nh_dev(rt); 169 + if (nft_fib6_info_nh_dev_match(nh_dev, dev)) 170 + return true; 171 + 172 + list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) { 173 + nh_dev = fib6_info_nh_dev(iter); 174 + 175 + if (nft_fib6_info_nh_dev_match(nh_dev, dev)) 176 + return true; 177 + } 178 + 179 + return false; 180 + } 181 + 156 182 void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs, 157 183 const struct nft_pktinfo *pkt) 158 184 { ··· 188 160 const struct net_device *found = NULL; 189 161 const struct net_device *oif = NULL; 190 162 u32 *dest = &regs->data[priv->dreg]; 163 + struct fib6_result res = {}; 191 164 struct ipv6hdr *iph, _iph; 192 165 struct flowi6 fl6 = { 193 166 .flowi6_iif = LOOPBACK_IFINDEX, 194 167 .flowi6_proto = pkt->tprot, 195 168 .flowi6_uid = sock_net_uid(nft_net(pkt), NULL), 196 169 }; 197 - struct rt6_info *rt; 198 - int lookup_flags; 170 + int lookup_flags, ret; 199 171 200 172 if (nft_fib_can_skip(pkt)) { 201 173 nft_fib_store_result(dest, priv, nft_in(pkt)); ··· 221 193 lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif, iph); 222 194 223 195 *dest = 0; 224 - rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, pkt->skb, 225 - lookup_flags); 226 - if (rt->dst.error) 227 - goto put_rt_err; 228 - 229 - /* Should not see RTF_LOCAL here */ 230 - if (rt->rt6i_flags & (RTF_REJECT | RTF_ANYCAST | RTF_LOCAL)) 231 - goto put_rt_err; 196 + ret = nft_fib6_lookup(nft_net(pkt), &fl6, &res, lookup_flags); 197 + if (ret || res.fib6_flags & (RTF_REJECT | RTF_ANYCAST | RTF_LOCAL)) 198 + return; 232 199 233 200 if (!oif) { 234 - found = rt->rt6i_idev->dev; 201 + found = fib6_info_nh_dev(res.f6i); 235 202 } else { 236 - if (oif == rt->rt6i_idev->dev || 237 - l3mdev_master_ifindex_rcu(rt->rt6i_idev->dev) == oif->ifindex) 203 + if (nft_fib6_info_nh_uses_dev(res.f6i, oif)) 238 204 found = oif; 239 205 } 240 - 241 206 nft_fib_store_result(dest, priv, found); 242 - put_rt_err: 243 - ip6_rt_put(rt); 244 207 } 245 208 EXPORT_SYMBOL_GPL(nft_fib6_eval); 246 209