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

ipv4: Elide fib_validate_source() completely when possible.

If rpfilter is off (or the SKB has an IPSEC path) and there are not
tclassid users, we don't have to do anything at all when
fib_validate_source() is invoked besides setting the itag to zero.

We monitor tclassid uses with a counter (modified only under RTNL and
marked __read_mostly) and we protect the fib_validate_source() real
work with a test against this counter and whether rpfilter is to be
done.

Having a way to know whether we need no tclassid processing or not
also opens the door for future optimized rpfilter algorithms that do
not perform full FIB lookups.

Signed-off-by: David S. Miller <davem@davemloft.net>

+59 -9
+1
include/net/fib_rules.h
··· 52 52 struct sk_buff *, 53 53 struct fib_rule_hdr *, 54 54 struct nlattr **); 55 + void (*delete)(struct fib_rule *); 55 56 int (*compare)(struct fib_rule *, 56 57 struct fib_rule_hdr *, 57 58 struct nlattr **);
+5
include/net/ip_fib.h
··· 235 235 u8 tos, int oif, struct net_device *dev, 236 236 struct in_device *idev, u32 *itag); 237 237 extern void fib_select_default(struct fib_result *res); 238 + #ifdef CONFIG_IP_ROUTE_CLASSID 239 + extern int fib_num_tclassid_users; 240 + #else 241 + #define fib_num_tclassid_users 0 242 + #endif 238 243 239 244 /* Exported by fib_semantics.c */ 240 245 extern int ip_fib_check_default(__be32 gw, struct net_device *dev);
+4
net/core/fib_rules.c
··· 151 151 152 152 list_for_each_entry_safe(rule, tmp, &ops->rules_list, list) { 153 153 list_del_rcu(&rule->list); 154 + if (ops->delete) 155 + ops->delete(rule); 154 156 fib_rule_put(rule); 155 157 } 156 158 } ··· 501 499 502 500 notify_rule_change(RTM_DELRULE, rule, ops, nlh, 503 501 NETLINK_CB(skb).pid); 502 + if (ops->delete) 503 + ops->delete(rule); 504 504 fib_rule_put(rule); 505 505 flush_route_cache(ops); 506 506 rules_ops_put(ops);
+24 -8
net/ipv4/fib_frontend.c
··· 31 31 #include <linux/if_addr.h> 32 32 #include <linux/if_arp.h> 33 33 #include <linux/skbuff.h> 34 + #include <linux/cache.h> 34 35 #include <linux/init.h> 35 36 #include <linux/list.h> 36 37 #include <linux/slab.h> ··· 218 217 return inet_select_addr(dev, ip_hdr(skb)->saddr, scope); 219 218 } 220 219 220 + #ifdef CONFIG_IP_ROUTE_CLASSID 221 + int fib_num_tclassid_users __read_mostly; 222 + #endif 223 + 221 224 /* Given (packet source, input interface) and optional (dst, oif, tos): 222 225 * - (main) check, that source is valid i.e. not broadcast or our local 223 226 * address. ··· 230 225 * - check, that packet arrived from expected physical interface. 231 226 * called with rcu_read_lock() 232 227 */ 233 - int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos, 234 - int oif, struct net_device *dev, struct in_device *idev, 235 - u32 *itag) 228 + static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, 229 + u8 tos, int oif, struct net_device *dev, 230 + int rpf, struct in_device *idev, u32 *itag) 236 231 { 237 - int ret, no_addr, rpf, accept_local; 232 + int ret, no_addr, accept_local; 238 233 struct fib_result res; 239 234 struct flowi4 fl4; 240 235 struct net *net; ··· 247 242 fl4.flowi4_tos = tos; 248 243 fl4.flowi4_scope = RT_SCOPE_UNIVERSE; 249 244 250 - no_addr = rpf = accept_local = 0; 245 + no_addr = accept_local = 0; 251 246 no_addr = idev->ifa_list == NULL; 252 - 253 - /* Ignore rp_filter for packets protected by IPsec. */ 254 - rpf = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev); 255 247 256 248 accept_local = IN_DEV_ACCEPT_LOCAL(idev); 257 249 fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0; ··· 303 301 return -EINVAL; 304 302 e_rpf: 305 303 return -EXDEV; 304 + } 305 + 306 + /* Ignore rp_filter for packets protected by IPsec. */ 307 + int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, 308 + u8 tos, int oif, struct net_device *dev, 309 + struct in_device *idev, u32 *itag) 310 + { 311 + int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev); 312 + 313 + if (!r && !fib_num_tclassid_users) { 314 + *itag = 0; 315 + return 0; 316 + } 317 + return __fib_validate_source(skb, src, dst, tos, oif, dev, r, idev, itag); 306 318 } 307 319 308 320 static inline __be32 sk_extract_addr(struct sockaddr *addr)
+15 -1
net/ipv4/fib_rules.c
··· 169 169 rule4->dst = nla_get_be32(tb[FRA_DST]); 170 170 171 171 #ifdef CONFIG_IP_ROUTE_CLASSID 172 - if (tb[FRA_FLOW]) 172 + if (tb[FRA_FLOW]) { 173 173 rule4->tclassid = nla_get_u32(tb[FRA_FLOW]); 174 + if (rule4->tclassid) 175 + fib_num_tclassid_users++; 176 + } 174 177 #endif 175 178 176 179 rule4->src_len = frh->src_len; ··· 185 182 err = 0; 186 183 errout: 187 184 return err; 185 + } 186 + 187 + static void fib4_rule_delete(struct fib_rule *rule) 188 + { 189 + #ifdef CONFIG_IP_ROUTE_CLASSID 190 + struct fib4_rule *rule4 = (struct fib4_rule *) rule; 191 + 192 + if (rule4->tclassid) 193 + fib_num_tclassid_users--; 194 + #endif 188 195 } 189 196 190 197 static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, ··· 269 256 .action = fib4_rule_action, 270 257 .match = fib4_rule_match, 271 258 .configure = fib4_rule_configure, 259 + .delete = fib4_rule_delete, 272 260 .compare = fib4_rule_compare, 273 261 .fill = fib4_rule_fill, 274 262 .default_pref = fib_default_rule_pref,
+10
net/ipv4/fib_semantics.c
··· 163 163 return; 164 164 } 165 165 fib_info_cnt--; 166 + #ifdef CONFIG_IP_ROUTE_CLASSID 167 + change_nexthops(fi) { 168 + if (nexthop_nh->nh_tclassid) 169 + fib_num_tclassid_users--; 170 + } endfor_nexthops(fi); 171 + #endif 166 172 call_rcu(&fi->rcu, free_fib_info_rcu); 167 173 } 168 174 ··· 427 421 #ifdef CONFIG_IP_ROUTE_CLASSID 428 422 nla = nla_find(attrs, attrlen, RTA_FLOW); 429 423 nexthop_nh->nh_tclassid = nla ? nla_get_u32(nla) : 0; 424 + if (nexthop_nh->nh_tclassid) 425 + fib_num_tclassid_users++; 430 426 #endif 431 427 } 432 428 ··· 823 815 nh->nh_flags = cfg->fc_flags; 824 816 #ifdef CONFIG_IP_ROUTE_CLASSID 825 817 nh->nh_tclassid = cfg->fc_flow; 818 + if (nh->nh_tclassid) 819 + fib_num_tclassid_users++; 826 820 #endif 827 821 #ifdef CONFIG_IP_ROUTE_MULTIPATH 828 822 nh->nh_weight = 1;