Skip to content

Commit

Permalink
ipv4: Elide fib_validate_source() completely when possible.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David S. Miller committed Jun 29, 2012
1 parent b8c8430 commit 7a9bc9b
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 9 deletions.
1 change: 1 addition & 0 deletions include/net/fib_rules.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ struct fib_rules_ops {
struct sk_buff *,
struct fib_rule_hdr *,
struct nlattr **);
void (*delete)(struct fib_rule *);
int (*compare)(struct fib_rule *,
struct fib_rule_hdr *,
struct nlattr **);
Expand Down
5 changes: 5 additions & 0 deletions include/net/ip_fib.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ extern int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
u8 tos, int oif, struct net_device *dev,
struct in_device *idev, u32 *itag);
extern void fib_select_default(struct fib_result *res);
#ifdef CONFIG_IP_ROUTE_CLASSID
extern int fib_num_tclassid_users;
#else
#define fib_num_tclassid_users 0
#endif

/* Exported by fib_semantics.c */
extern int ip_fib_check_default(__be32 gw, struct net_device *dev);
Expand Down
4 changes: 4 additions & 0 deletions net/core/fib_rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ static void fib_rules_cleanup_ops(struct fib_rules_ops *ops)

list_for_each_entry_safe(rule, tmp, &ops->rules_list, list) {
list_del_rcu(&rule->list);
if (ops->delete)
ops->delete(rule);
fib_rule_put(rule);
}
}
Expand Down Expand Up @@ -499,6 +501,8 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)

notify_rule_change(RTM_DELRULE, rule, ops, nlh,
NETLINK_CB(skb).pid);
if (ops->delete)
ops->delete(rule);
fib_rule_put(rule);
flush_route_cache(ops);
rules_ops_put(ops);
Expand Down
32 changes: 24 additions & 8 deletions net/ipv4/fib_frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <linux/if_addr.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/cache.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/slab.h>
Expand Down Expand Up @@ -217,6 +218,10 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
return inet_select_addr(dev, ip_hdr(skb)->saddr, scope);
}

#ifdef CONFIG_IP_ROUTE_CLASSID
int fib_num_tclassid_users __read_mostly;
#endif

/* Given (packet source, input interface) and optional (dst, oif, tos):
* - (main) check, that source is valid i.e. not broadcast or our local
* address.
Expand All @@ -225,11 +230,11 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
* - check, that packet arrived from expected physical interface.
* called with rcu_read_lock()
*/
int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos,
int oif, struct net_device *dev, struct in_device *idev,
u32 *itag)
static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
u8 tos, int oif, struct net_device *dev,
int rpf, struct in_device *idev, u32 *itag)
{
int ret, no_addr, rpf, accept_local;
int ret, no_addr, accept_local;
struct fib_result res;
struct flowi4 fl4;
struct net *net;
Expand All @@ -242,12 +247,9 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos,
fl4.flowi4_tos = tos;
fl4.flowi4_scope = RT_SCOPE_UNIVERSE;

no_addr = rpf = accept_local = 0;
no_addr = accept_local = 0;
no_addr = idev->ifa_list == NULL;

/* Ignore rp_filter for packets protected by IPsec. */
rpf = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);

accept_local = IN_DEV_ACCEPT_LOCAL(idev);
fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0;

Expand Down Expand Up @@ -303,6 +305,20 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos,
return -EXDEV;
}

/* Ignore rp_filter for packets protected by IPsec. */
int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
u8 tos, int oif, struct net_device *dev,
struct in_device *idev, u32 *itag)
{
int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);

if (!r && !fib_num_tclassid_users) {
*itag = 0;
return 0;
}
return __fib_validate_source(skb, src, dst, tos, oif, dev, r, idev, itag);
}

static inline __be32 sk_extract_addr(struct sockaddr *addr)
{
return ((struct sockaddr_in *) addr)->sin_addr.s_addr;
Expand Down
16 changes: 15 additions & 1 deletion net/ipv4/fib_rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,11 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
rule4->dst = nla_get_be32(tb[FRA_DST]);

#ifdef CONFIG_IP_ROUTE_CLASSID
if (tb[FRA_FLOW])
if (tb[FRA_FLOW]) {
rule4->tclassid = nla_get_u32(tb[FRA_FLOW]);
if (rule4->tclassid)
fib_num_tclassid_users++;
}
#endif

rule4->src_len = frh->src_len;
Expand All @@ -184,6 +187,16 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
return err;
}

static void fib4_rule_delete(struct fib_rule *rule)
{
#ifdef CONFIG_IP_ROUTE_CLASSID
struct fib4_rule *rule4 = (struct fib4_rule *) rule;

if (rule4->tclassid)
fib_num_tclassid_users--;
#endif
}

static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
struct nlattr **tb)
{
Expand Down Expand Up @@ -256,6 +269,7 @@ static const struct fib_rules_ops __net_initdata fib4_rules_ops_template = {
.action = fib4_rule_action,
.match = fib4_rule_match,
.configure = fib4_rule_configure,
.delete = fib4_rule_delete,
.compare = fib4_rule_compare,
.fill = fib4_rule_fill,
.default_pref = fib_default_rule_pref,
Expand Down
10 changes: 10 additions & 0 deletions net/ipv4/fib_semantics.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ void free_fib_info(struct fib_info *fi)
return;
}
fib_info_cnt--;
#ifdef CONFIG_IP_ROUTE_CLASSID
change_nexthops(fi) {
if (nexthop_nh->nh_tclassid)
fib_num_tclassid_users--;
} endfor_nexthops(fi);
#endif
call_rcu(&fi->rcu, free_fib_info_rcu);
}

Expand Down Expand Up @@ -421,6 +427,8 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
#ifdef CONFIG_IP_ROUTE_CLASSID
nla = nla_find(attrs, attrlen, RTA_FLOW);
nexthop_nh->nh_tclassid = nla ? nla_get_u32(nla) : 0;
if (nexthop_nh->nh_tclassid)
fib_num_tclassid_users++;
#endif
}

Expand Down Expand Up @@ -815,6 +823,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
nh->nh_flags = cfg->fc_flags;
#ifdef CONFIG_IP_ROUTE_CLASSID
nh->nh_tclassid = cfg->fc_flow;
if (nh->nh_tclassid)
fib_num_tclassid_users++;
#endif
#ifdef CONFIG_IP_ROUTE_MULTIPATH
nh->nh_weight = 1;
Expand Down

0 comments on commit 7a9bc9b

Please sign in to comment.